using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    abstract class ServerMessage
    {
        protected TCPClient.ClientMessageType clientMessageToReturn;
        protected TCPServer.ServerRequestMessage serverMessageExpected;
        public abstract System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml);

        public TCPClient.ClientMessageType ClientMessageToReturn
        {
            get
            {
                return clientMessageToReturn;
            }
        }

        public TCPServer.ServerRequestMessage ServerMessageExpected
        {
            get
            {
                return serverMessageExpected;
            }
        }

        public static ServerMessage Deserialise(System.Xml.XmlNode node)
        {
            if(node.Name == "ServerMessage")
            {
                switch(node.Attributes["ServerMessageType"].Value)
                {
                    case "DisplayWeather":
                        return (ServerMessage)DisplayWeather.Deserialise(node);
                    case "AskForDefenderOptions":
                        return (ServerMessage)ServerMessageAskForDefenderOptions.Deserialise(node);
                    case "DoDefenderCombat":
                        return (ServerMessage)ServerMessageDoDefenderCombat.Deserialise(node);
                    case "AskAttackerToAssignLossesReturn":
                        return (ServerMessage)ServerMessageAssignLossesReturn.Deserialise(node);
                    case "AskDefenderToAssignLosses":
                        return (ServerMessage)ServerMessageAskDefenderToAssignLosses.Deserialise(node);
                    case "ServerMessageAskDefenderForCounterAttack":
                        return (ServerMessage)ServerMessageAskDefenderForCounterAttack.Deserialise(node);
                    case "ServerMessageDisplayCalculatingSupply":
                        return (ServerMessage)ServerMessageDisplayCalculatingSupply.Deserialise(node);
                    case "ServerMessageDoStrategicBombingWarfare":
                        return (ServerMessage)ServerMessageDoStrategicBombingWarfare.Deserialise(node);
                    case "ServerMessageReportStrategicBombingWarfare":
                        return (ServerMessage)ServerMessageReportStrategicBombingWarfare.Deserialise(node);
                    case "ServerMessageDoStrategicUBoatWarfare":
                        return (ServerMessage)ServerMessageDoStrategicUBoatWarfare.Deserialise(node);
                    case "ServerMessageReportStrategicUBoatWarfare":
                        return (ServerMessage)ServerMessageReportStrategicUBoatWarfare.Deserialise(node);
                    case "ServerMessageDoStrategicVWeaponWarfare":
                        return (ServerMessage)ServerMessageDoStrategicVWeaponWarfare.Deserialise(node);
                    case "ServerMessageReportStrategicVWeaponWarfare":
                        return (ServerMessage)ServerMessageReportStrategicVWeaponWarfare.Deserialise(node);
                    case "ServerMessageDoAxisProductionPhase":
                        return (ServerMessage)ServerMessageDoAxisProductionPhase.Deserialise(node);
                    case "ServerMessageDoAlliedProductionPhase":
                        return (ServerMessage)ServerMessageDoAlliedProductionPhase.Deserialise(node);
                    case "ServerMessageAskForStrategicWarfareInterception":
                        return (ServerMessage)ServerMessageAskForStrategicWarfareInterception.Deserialise(node);
                    case "ServerMessageDoSupplySelection":
                        return (ServerMessage)ServerMessageDoSupplySelection.Deserialise(node);
                    case "ServerMessageDoInitialOps":
                        return (ServerMessage)ServerMessageDoInitialOps.Deserialise(node);
                    case "ServerMessageDoBreakThroughOps":
                        return (ServerMessage)ServerMessageDoBreakThroughOps.Deserialise(node);
                    case "ServerMessageDoInitialStrategicMovement":
                        return (ServerMessage)ServerMessageDoInitialStrategicMovement.Deserialise(node);
                    case "ServerMessageDoNewCountryDeployment":
                        return (ServerMessage)ServerMessageDoNewCountryDeployment.Deserialise(node);
                    case "ServerMessageAskForNavalInterception":
                        return (ServerMessage)ServerMessageAskForNavalInterception.Deserialise(node);
                    case "ServerMessageReportForNavalInterception":
                        return (ServerMessage)ServerMessageReportForNavalInterception.Deserialise(node);
                    case "ServerMessageDoBreakThroughCombat":
                        return (ServerMessage)ServerMessageDoBreakThroughCombat.Deserialise(node);
                    case "ServerMessageDoInitialCombatPhase":
                        return (ServerMessage)ServerMessageDoInitialCombatPhase.Deserialise(node);
                    case "ServerMessageAskForGSUCombatCasualties":
                        return (ServerMessage)ServerMessageAskForGSUCombatCasualties.Deserialise(node);
                    case "ServerMessageAskAttackerToAssignLosses":
                        return (ServerMessage)ServerMessageAskAttackerToAssignLosses.Deserialise(node);
                    case "ServerMessageAskDefenderForRetreatBeforeCombatMoves":
                        return (ServerMessage)ServerMessageAskDefenderForRetreatBeforeCombatMoves.Deserialise(node);
                    case "ServerMessageAskForBreakThroughOption":
                        return (ServerMessage)ServerMessageAskForBreakThroughOption.Deserialise(node);
                    case "ServerMessageDoBreakThroughStrategicMovement":
                        return (ServerMessage)ServerMessageDoBreakThroughStrategicMovement.Deserialise(node);
                    case "ServerMessageInformPlayerOfConquest":
                        return (ServerMessage)ServerMessageInformPlayerOfConquest.Deserialise(node);
                    case "ServerMessageDoFleetPointTransfers":
                        return (ServerMessage)ServerMessageDoFleetPointTransfers.Deserialise(node);
                    case "ServerMessageDoFortressOverStackMoves":
                        return (ServerMessage)ServerMessageDoFortressOverStackMoves.Deserialise(node);
                    case "ServerMessageAskAxisPlayerForVichy":
                        return (ServerMessage)ServerMessageAskAxisPlayerForVichy.Deserialise(node);
                    case "ServerMessageInformPlayer":
                        return (ServerMessage)ServerMessageInformPlayer.Deserialise(node);
                    case "ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses":
                        return (ServerMessage)ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses.Deserialise(node);
                    case "ServerMessageInformPlayerOfVictory":
                        return (ServerMessage)ServerMessageInformPlayerOfVictory.Deserialise(node);
                    case "ServerMessageAssignBoolReturn":
                        return (ServerMessage)ServerMessageAssignBoolReturn.Deserialise(node);
                    case "ServerMessageDeploymentMovesReturn":
                        return (ServerMessage)ServerMessageDeploymentMovesReturn.Deserialise(node);
                    case "ServerMessageAskForDefenderOptionsReturn":
                        return (ServerMessage)ServerMessageAskForDefenderOptionsReturn.Deserialise(node);
                    case "ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn":
                        return (ServerMessage)ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn.Deserialise(node);
                    case "ServerMessageAskForGSUCombatCasualtiesReturn":
                        return (ServerMessage)ServerMessageAskForGSUCombatCasualtiesReturn.Deserialise(node);
                    case "ServerMessageAskDefenderForCounterAttackReturn":
                        return (ServerMessage)ServerMessageAskDefenderForCounterAttackReturn.Deserialise(node);
                    case "ServerMessageInformPlayerOfChangeOfPhase":
                        return (ServerMessage)ServerMessageInformPlayerOfChangeOfPhase.Deserialise(node);
                }
            }

            throw new InvalidOperationException("Could not parse server message");
        }

        
    }

    abstract class ServerMessagePlayerCall : ServerMessage
    {
        public abstract ClientMessage CallPlayer(IPlayer player);
    };

    class DisplayWeather : ServerMessagePlayerCall
    {
        private GameController.playerType playerType;
        private GameState.Weather southernWeather;
        private GameState.Weather westernWeather;
        private GameState.Weather easternWeather;
        private MapInfo.gameDateWeatherType weatherType;
        private uint axisDieRoll;
        private uint alliedDieRoll;
        public DisplayWeather(GameController.playerType playerType, GameState.Weather southernWeather, GameState.Weather westernWeather, GameState.Weather easternWeather, MapInfo.gameDateWeatherType weatherType, uint axisDieRoll, uint alliedDieRoll)
        {
            this.playerType = playerType;
            this.clientMessageToReturn = TCPClient.ClientMessageType.DisplayWeather;
            this.serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
            this.southernWeather = southernWeather;
            this.westernWeather = westernWeather;
            this.easternWeather = easternWeather;
            this.weatherType = weatherType;
            this.axisDieRoll = axisDieRoll;
            this.alliedDieRoll = alliedDieRoll;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "DisplayWeather";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);
            System.Xml.XmlNode PlayerTypeNode = xml.CreateElement("PlayerType");
            PlayerTypeNode.InnerText = Enum.GetName(typeof(GameController.playerType), playerType);
            nodeToReturn.AppendChild(PlayerTypeNode);
            System.Xml.XmlNode SouthernWeatherNode = xml.CreateElement("SouthernWeather");
            SouthernWeatherNode.InnerText = Enum.GetName(typeof(GameState.Weather), southernWeather);
            nodeToReturn.AppendChild(SouthernWeatherNode);
            System.Xml.XmlNode WesternWeatherNode = xml.CreateElement("WesternWeather");
            WesternWeatherNode.InnerText = Enum.GetName(typeof(GameState.Weather), westernWeather);
            nodeToReturn.AppendChild(WesternWeatherNode);
            System.Xml.XmlNode EasternWeatherNode = xml.CreateElement("EasternWeather");
            EasternWeatherNode.InnerText = Enum.GetName(typeof(GameState.Weather), easternWeather);
            nodeToReturn.AppendChild(EasternWeatherNode);
            System.Xml.XmlNode WeatherTypeNode = xml.CreateElement("WeatherType");
            WeatherTypeNode.InnerText = Enum.GetName(typeof(MapInfo.gameDateWeatherType), weatherType);
            nodeToReturn.AppendChild(WeatherTypeNode);
            System.Xml.XmlNode AxisDieRollNode = xml.CreateElement("AxisDieRoll");
            AxisDieRollNode.InnerText = axisDieRoll.ToString();
            nodeToReturn.AppendChild(AxisDieRollNode);
            System.Xml.XmlNode AlliedDieRollNode = xml.CreateElement("AlliedDieRoll");
            AlliedDieRollNode.InnerText = alliedDieRoll.ToString();
            nodeToReturn.AppendChild(AlliedDieRollNode);
            return nodeToReturn;
        }

        public new static DisplayWeather Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType playerType = GameController.playerType.AlliedPlayer;
            GameState.Weather southernWeather = GameState.Weather.Clear;
            GameState.Weather westernWeather = GameState.Weather.Clear;;
            GameState.Weather easternWeather = GameState.Weather.Clear;;
            MapInfo.gameDateWeatherType weatherType = MapInfo.gameDateWeatherType.clearWeatherAll;
            uint axisDieRoll = 0;
            uint alliedDieRoll = 0;

            foreach(System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "PlayerType")
                    playerType = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if(childNode.Name == "SouthernWeather")
                    southernWeather = (GameState.Weather)Enum.Parse(typeof(GameState.Weather),childNode.InnerText);
                if(childNode.Name == "WesternWeather")
                    westernWeather = (GameState.Weather)Enum.Parse(typeof(GameState.Weather),childNode.InnerText);
                if(childNode.Name == "EasternWeather")
                    easternWeather = (GameState.Weather)Enum.Parse(typeof(GameState.Weather),childNode.InnerText);
                if(childNode.Name == "WeatherType")
                    weatherType = (MapInfo.gameDateWeatherType)Enum.Parse(typeof(MapInfo.gameDateWeatherType), childNode.InnerText);
                if(childNode.Name == "AxisDieRoll")
                    axisDieRoll = (uint)Int32.Parse(childNode.InnerText);
                if(childNode.Name == "AlliedDieRoll")
                    alliedDieRoll = (uint)Int32.Parse(childNode.InnerText);
            }

            return new DisplayWeather(playerType, southernWeather, westernWeather, easternWeather, weatherType, axisDieRoll, alliedDieRoll);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.DisplayWeatherDetermination(playerType, southernWeather, westernWeather, easternWeather, weatherType, axisDieRoll, alliedDieRoll);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageInformPlayerOfChangeOfPhase : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private GameTurn.GameDate gameDate;
        private GameTurn.GameSubPhase gameSubPhase;
        private GameState gameStateToUpdate;

        public ServerMessageInformPlayerOfChangeOfPhase(GameController.playerType player, GameTurn.GameDate gameDate, GameTurn.GameSubPhase gameSubPhase, GameState gameStateToUpdate)
        {
            this.player = player;
            this.gameDate = gameDate;
            this.gameSubPhase = gameSubPhase;
            this.gameStateToUpdate = gameStateToUpdate;
            this.clientMessageToReturn = TCPClient.ClientMessageType.InformPlayerOfChangeOfPhase;
            this.serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageInformPlayerOfChangeOfPhase";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode PlayerTypeNode = xml.CreateElement("Player");
            PlayerTypeNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerTypeNode);

            System.Xml.XmlNode GameSubPhaseNode = xml.CreateElement("GameSubPhase");
            GameSubPhaseNode.InnerText = Enum.GetName(typeof(GameTurn.GameSubPhase), gameSubPhase);
            nodeToReturn.AppendChild(GameSubPhaseNode);

            System.Xml.XmlNode GameDateNode = xml.CreateElement("GameDate");
            GameDateNode.InnerText = Enum.GetName(typeof(GameTurn.GameDate), gameDate);
            nodeToReturn.AppendChild(GameDateNode);

            nodeToReturn.AppendChild(gameStateToUpdate.SerialiseGetGameStateNode(xml, gameDate));
            return nodeToReturn;
        }

        public new static ServerMessageInformPlayerOfChangeOfPhase Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            GameTurn.GameDate gameDate = GameTurn.GameDate.JanFeb40;
            GameTurn.GameSubPhase gameSubPhase = GameTurn.GameSubPhase.BreakThrough;
            GameState gameStateToUpdate = null;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch(childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "GameSubPhase":
                        gameSubPhase = (GameTurn.GameSubPhase)Enum.Parse(typeof(GameTurn.GameSubPhase), childNode.InnerText);
                        break;
                    case "GameDate":
                        gameDate = (GameTurn.GameDate)Enum.Parse(typeof(GameTurn.GameDate), childNode.InnerText);
                        break;
                    case "EuropeEngulfedGameState":
                        {
                            gameStateToUpdate = GameState.Deserialise(childNode);
                        }
                        break;
                }
            }

            return new ServerMessageInformPlayerOfChangeOfPhase(player, gameDate, gameSubPhase, gameStateToUpdate);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.InformPlayerOfChangeOfPhase(this.player, gameDate, gameSubPhase, gameStateToUpdate);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDisplayCalculatingSupply : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDisplayCalculatingSupply(GameController.playerType player)
        {
            this.player = player;
            this.clientMessageToReturn = TCPClient.ClientMessageType.DisplayCalculatingSupply;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDisplayCalculatingSupply";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);
            System.Xml.XmlNode PlayerTypeNode = xml.CreateElement("PlayerType");
            PlayerTypeNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerTypeNode);
            return nodeToReturn;
        }

        public new static ServerMessageDisplayCalculatingSupply Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "PlayerType")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
            }

            return new ServerMessageDisplayCalculatingSupply(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            player.DisplayCalculatingSupply(this.player);
            return null;
        }
    };

    class ServerMessageAskForDefenderOptions : ServerMessagePlayerCall
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private bool selectGSUs;
        private bool breakThroughCombat;
        private bool assault;
        private List<MapInfo.CountryID> countriesSpendingSA;
        private GameController.defenderOptions defenderOptionsReturned;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ServerMessageAskForDefenderOptions(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool selectGSUs, bool breakThroughCombat, bool assault, List<MapInfo.CountryID> countriesSpendingSA, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.defendingPlayer = defendingPlayer;
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForDefenderOptions;
            serverMessageExpected = TCPServer.ServerRequestMessage.AskForDefenderOptionsReturn;
            this.regionID = regionID;
            this.selectGSUs = selectGSUs;
            this.breakThroughCombat = breakThroughCombat;
            this.assault = assault;
            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "AskForDefenderOptions";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);
            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);
            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);
            System.Xml.XmlNode SelectGSUsNode = xml.CreateElement("SelectGSUs");
            SelectGSUsNode.InnerText = selectGSUs.ToString();
            nodeToReturn.AppendChild(SelectGSUsNode);
            System.Xml.XmlNode BreakThroughCombatNode = xml.CreateElement("BreakThroughCombat");
            BreakThroughCombatNode.InnerText = breakThroughCombat.ToString();
            nodeToReturn.AppendChild(BreakThroughCombatNode);
            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);
            System.Xml.XmlNode CountriesSpendingSANode = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSANode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSANode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskForDefenderOptions Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            bool selectGSUs = false;
            bool breakThroughCombat = false;
            bool assault = false;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "SelectGSUs")
                    selectGSUs = bool.Parse(childNode.InnerText);
                if (childNode.Name == "BreakThroughCombat")
                    breakThroughCombat = bool.Parse(childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CountriesSpendingSA")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ServerMessageAskForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            this.defenderOptionsReturned = player.AskDefenderForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);
            return new ClientMessageAskForDefenderOptionsReturn(this.defenderOptionsReturned);
        }
    }

    class ServerMessageDoDefenderCombat : ServerMessagePlayerCall
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private bool counterAttack;
        private List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ServerMessageDoDefenderCombat(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat, List<CombatMove> combatMovesAlreadyTaken)
        {
            
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoDefenderCombat;
            serverMessageExpected = TCPServer.ServerRequestMessage.DoDefenderCombatReturn;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.counterAttack = counterAttack;
            if (countriesSpendingSAForBreakThroughCombat != null)
                this.countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>(countriesSpendingSAForBreakThroughCombat);
            else
                this.countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();

        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "DoDefenderCombat";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CountriesSpendingSAForBreakThroughCombatNode = xml.CreateElement("CountriesSpendingSAForBreakThroughCombat");
            foreach (MapInfo.CountryID country in countriesSpendingSAForBreakThroughCombat)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSAForBreakThroughCombatNode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSAForBreakThroughCombatNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ServerMessageDoDefenderCombat Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID,int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            bool counterAttack = false;
            List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CountriesSpendingSAForBreakThroughCombat")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSAForBreakThroughCombat.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ServerMessageDoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            Dictionary<PlayingPiece, int> returnValue = player.DoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);
            return new ClientMessageDoDefenderCombatReturn(returnValue);
        }
    }

    class ServerMessageAskDefenderToAssignLosses : ServerMessagePlayerCall
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID battleRegionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private int numInfantryLosses;
        private int numArmorLosses;
        private bool counterAttack;
        private List<CombatMove> combatMovesAlreadyTaken;
        public ServerMessageAskDefenderToAssignLosses(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskDefenderToAssignLosses;
            serverMessageExpected = TCPServer.ServerRequestMessage.AssignLossesReturn;
            this.defendingPlayer = defendingPlayer;
            this.battleRegionID = battleRegionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.numInfantryLosses = numInfantryLosses;
            this.numArmorLosses = numArmorLosses;
            this.counterAttack = counterAttack;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "AskDefenderToAssignLosses";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode BattleRegionIDNode = xml.CreateElement("BattleRegionID");
            BattleRegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), battleRegionID);
            nodeToReturn.AppendChild(BattleRegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode NumInfantryLossesNode = xml.CreateElement("NumInfantryLosses");
            NumInfantryLossesNode.InnerText = numInfantryLosses.ToString();
            nodeToReturn.AppendChild(NumInfantryLossesNode);

            System.Xml.XmlNode NumArmorLossesNode = xml.CreateElement("NumArmorLosses");
            NumArmorLossesNode.InnerText = numArmorLosses.ToString();
            nodeToReturn.AppendChild(NumArmorLossesNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskDefenderToAssignLosses Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID battleRegionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            int numInfantryLosses = 0;
            int numArmorLosses = 0;
            bool counterAttack = false;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "BattleRegionID")
                    battleRegionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "NumInfantryLosses")
                    numInfantryLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumArmorLosses")
                    numArmorLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ServerMessageAskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            Dictionary<PlayingPiece, int> returnValue = player.AskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);
            return new ClientMessageAssignLossesReturn(returnValue);
        }
    };

    class ServerMessageAskDefenderForCounterAttack : ServerMessagePlayerCall
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID battleRegion;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ServerMessageAskDefenderForCounterAttack(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegion, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskDefenderForCounterAttack;
            serverMessageExpected = TCPServer.ServerRequestMessage.CounterAttackReturn;
            this.defendingPlayer = defendingPlayer;
            this.battleRegion = battleRegion;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskDefenderForCounterAttack";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode BattleRegionNode = xml.CreateElement("BattleRegion");
            BattleRegionNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), battleRegion);
            nodeToReturn.AppendChild(BattleRegionNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach(CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskDefenderForCounterAttack Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID battleRegion = MapInfo.RegionID.AtlanticOcean;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "BattleRegion")
                    battleRegion = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ServerMessageAskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            GameController.defenderCounterAttackOptions returnValue = player.AskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);
            return new ClientMessageDefenderCounterAttackOptionsReturn(returnValue);
        }
    };

    class ServerMessageDoStrategicBombingWarfare : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private uint originalWesternAlliedBombers;
        private uint originalWesternAlliedFighters;
        private uint WesternAlliedFlak;
        private uint originalGermanBombers;
        private uint originalGermanFighters;
        private uint GermanFlak;
        private uint targetedWERPProduction;
        private GameState.Weather currentWesternWeather;
        private GameTurn.GameDate currentGameDate;
        private GameTurn.GamePhase currentGamePhase;
        private bool upgradedEscorts;
        private bool upgradeBombers;

        public ServerMessageDoStrategicBombingWarfare(GameController.playerType player,
        uint originalWesternAlliedBombers, uint originalWesternAlliedFighters, uint WesternAlliedFlak, uint originalGermanBombers,
        uint originalGermanFighters, uint GermanFlak, uint targetedWERPProduction, GameState.Weather currentWesternWeather,
        GameTurn.GameDate currentGameDate, GameTurn.GamePhase currentGamePhase,
        bool upgradedEscorts, bool upgradeBombers)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoStrategicBombingWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.StratWarfareReturn;

            this.player = player;
            this.originalWesternAlliedBombers = originalWesternAlliedBombers;
            this.originalWesternAlliedFighters = originalWesternAlliedFighters;
            this.WesternAlliedFlak = WesternAlliedFlak;
            this.originalGermanBombers = originalGermanBombers;
            this.originalGermanFighters = originalGermanFighters;
            this.GermanFlak = GermanFlak;
            this.targetedWERPProduction = targetedWERPProduction;
            this.currentWesternWeather = currentWesternWeather;
            this.currentGameDate = currentGameDate;
            this.currentGamePhase = currentGamePhase;
            this.upgradedEscorts = upgradedEscorts;
            this.upgradeBombers = upgradeBombers;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoStrategicBombingWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            System.Xml.XmlNode OriginalWesternAlliedBombersNode = xml.CreateElement("OriginalWesternAlliedBombers");
            OriginalWesternAlliedBombersNode.InnerText = originalWesternAlliedBombers.ToString();
            nodeToReturn.AppendChild(OriginalWesternAlliedBombersNode);

            System.Xml.XmlNode OriginalWesternAlliedFightersNode = xml.CreateElement("OriginalWesternAlliedFighters");
            OriginalWesternAlliedFightersNode.InnerText = originalWesternAlliedFighters.ToString();
            nodeToReturn.AppendChild(OriginalWesternAlliedFightersNode);

            System.Xml.XmlNode WesternAlliedFlakNode = xml.CreateElement("WesternAlliedFlak");
            WesternAlliedFlakNode.InnerText = WesternAlliedFlak.ToString();
            nodeToReturn.AppendChild(WesternAlliedFlakNode);

            System.Xml.XmlNode OriginalGermanBombersNode = xml.CreateElement("OriginalGermanBombers");
            OriginalGermanBombersNode.InnerText = originalGermanBombers.ToString();
            nodeToReturn.AppendChild(OriginalGermanBombersNode);

            System.Xml.XmlNode OriginalGermanFightersNode = xml.CreateElement("OriginalGermanFighters");
            OriginalGermanFightersNode.InnerText = originalGermanFighters.ToString();
            nodeToReturn.AppendChild(OriginalGermanFightersNode);

            System.Xml.XmlNode GermanFlakNode = xml.CreateElement("GermanFlak");
            GermanFlakNode.InnerText = GermanFlak.ToString();
            nodeToReturn.AppendChild(GermanFlakNode);

            System.Xml.XmlNode TargetedWERPProductionNode = xml.CreateElement("TargetedWERPProduction");
            TargetedWERPProductionNode.InnerText = targetedWERPProduction.ToString();
            nodeToReturn.AppendChild(TargetedWERPProductionNode);

            System.Xml.XmlNode CurrentWesternWeatherNode = xml.CreateElement("CurrentWesternWeather");
            CurrentWesternWeatherNode.InnerText = Enum.GetName(typeof(GameState.Weather), currentWesternWeather);
            nodeToReturn.AppendChild(CurrentWesternWeatherNode);

            System.Xml.XmlNode CurrentGameDateNode = xml.CreateElement("CurrentGameDate");
            CurrentGameDateNode.InnerText = Enum.GetName(typeof(GameTurn.GameDate), currentGameDate);
            nodeToReturn.AppendChild(CurrentGameDateNode);

            System.Xml.XmlNode CurrentGamePhaseNode = xml.CreateElement("CurrentGamePhase");
            CurrentGamePhaseNode.InnerText = Enum.GetName(typeof(GameTurn.GamePhase), currentGamePhase);
            nodeToReturn.AppendChild(CurrentGamePhaseNode);

            System.Xml.XmlNode UpgradedEscortsNode = xml.CreateElement("UpgradedEscorts");
            UpgradedEscortsNode.InnerText = upgradedEscorts.ToString();
            nodeToReturn.AppendChild(UpgradedEscortsNode);

            System.Xml.XmlNode UpgradeBombersNode = xml.CreateElement("UpgradeBombers");
            UpgradeBombersNode.InnerText = upgradeBombers.ToString();
            nodeToReturn.AppendChild(UpgradeBombersNode);

            return nodeToReturn;
        }

        public new static ServerMessageDoStrategicBombingWarfare Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            uint originalWesternAlliedBombers = 0;
            uint originalWesternAlliedFighters = 0;
            uint WesternAlliedFlak = 0;
            uint originalGermanBombers = 0;
            uint originalGermanFighters = 0;
            uint GermanFlak = 0;
            uint targetedWERPProduction = 0;
            GameState.Weather currentWesternWeather = GameState.Weather.Clear;
            GameTurn.GameDate currentGameDate = GameTurn.GameDate.JanFeb40;
            GameTurn.GamePhase currentGamePhase = GameTurn.GamePhase.AlliedPlayerTurn;
            bool upgradedEscorts = false;
            bool upgradeBombers = false;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "OriginalWesternAlliedBombers")
                    originalWesternAlliedBombers = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalWesternAlliedFighters")
                    originalWesternAlliedFighters = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "WesternAlliedFlak")
                    WesternAlliedFlak = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalGermanBombers")
                    originalGermanBombers = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalGermanFighters")
                    originalGermanFighters = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "GermanFlak")
                    GermanFlak = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "TargetedWERPProduction")
                    targetedWERPProduction = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CurrentWesternWeather")
                    currentWesternWeather = (GameState.Weather)Enum.Parse(typeof(GameState.Weather), childNode.InnerText);
                if (childNode.Name == "CurrentGameDate")
                    currentGameDate = (GameTurn.GameDate)Enum.Parse(typeof(GameTurn.GameDate), childNode.InnerText);
                if (childNode.Name == "CurrentGamePhase")
                    currentGamePhase = (GameTurn.GamePhase)Enum.Parse(typeof(GameTurn.GamePhase), childNode.InnerText);
                if (childNode.Name == "UpgradedEscorts")
                    upgradedEscorts = bool.Parse(childNode.InnerText);
                if (childNode.Name == "UpgradeBombers")
                    upgradeBombers = bool.Parse(childNode.InnerText);
            }

            return new ServerMessageDoStrategicBombingWarfare(player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<StratWarfareMove> returnValue = player.DoStrategicBombingWarfare(this.player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers);
            return new ClientMessageDoStrategicBombingWarfareReturn(returnValue);
        }
    };

    class ServerMessageReportStrategicBombingWarfare : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private uint originalWesternAlliedBombers;
        private uint originalWesternAlliedFighters;
        private uint WesternAlliedFlak;
        private uint originalGermanBombers;
        private uint originalGermanFighters;
        private uint GermanFlak;
        private uint targetedWERPProduction;
        private GameState.Weather currentWesternWeather;
        private GameTurn.GameDate currentGameDate;
        private GameTurn.GamePhase currentGamePhase;
        private bool upgradedEscorts;
        private bool upgradeBombers;
        private bool operationOverlord;
        private int numEscortsShotDown;
        private int numInterceptorsShotDownByEscorts;
        private int numInterceptorsShotDownByBombers;
        private int numBombersShotDownByInterceptors;
        private int numBombersShotDownByFlak;
        private int numStrategicBombHits;

        public ServerMessageReportStrategicBombingWarfare(GameController.playerType player,
        uint originalWesternAlliedBombers, uint originalWesternAlliedFighters, uint WesternAlliedFlak, uint originalGermanBombers,
        uint originalGermanFighters, uint GermanFlak, uint targetedWERPProduction, GameState.Weather currentWesternWeather,
        GameTurn.GameDate currentGameDate, GameTurn.GamePhase currentGamePhase,
        bool upgradedEscorts, bool upgradeBombers,
        bool operationOverlord, int numEscortsShotDown, int numInterceptorsShotDownByEscorts, int numInterceptorsShotDownByBombers, int numBombersShotDownByInterceptors, int numBombersShotDownByFlak, int numStrategicBombHits)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.ReportStrategicBombingWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;

            this.player = player;
            this.originalWesternAlliedBombers = originalWesternAlliedBombers;
            this.originalWesternAlliedFighters = originalWesternAlliedFighters;
            this.WesternAlliedFlak = WesternAlliedFlak;
            this.originalGermanBombers = originalGermanBombers;
            this.originalGermanFighters = originalGermanFighters;
            this.GermanFlak = GermanFlak;
            this.targetedWERPProduction = targetedWERPProduction;
            this.currentWesternWeather = currentWesternWeather;
            this.currentGameDate = currentGameDate;
            this.currentGamePhase = currentGamePhase;
            this.upgradedEscorts = upgradedEscorts;
            this.upgradeBombers = upgradeBombers;
            this.operationOverlord = operationOverlord;
            this.numEscortsShotDown = numEscortsShotDown;
            this.numInterceptorsShotDownByEscorts = numInterceptorsShotDownByEscorts;
            this.numInterceptorsShotDownByBombers = numInterceptorsShotDownByBombers;
            this.numBombersShotDownByInterceptors = numBombersShotDownByInterceptors;
            this.numBombersShotDownByFlak = numBombersShotDownByFlak;
            this.numStrategicBombHits = numStrategicBombHits;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageReportStrategicBombingWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            System.Xml.XmlNode OriginalWesternAlliedBombersNode = xml.CreateElement("OriginalWesternAlliedBombers");
            OriginalWesternAlliedBombersNode.InnerText = originalWesternAlliedBombers.ToString();
            nodeToReturn.AppendChild(OriginalWesternAlliedBombersNode);

            System.Xml.XmlNode OriginalWesternAlliedFightersNode = xml.CreateElement("OriginalWesternAlliedFighters");
            OriginalWesternAlliedFightersNode.InnerText = originalWesternAlliedFighters.ToString();
            nodeToReturn.AppendChild(OriginalWesternAlliedFightersNode);

            System.Xml.XmlNode WesternAlliedFlakNode = xml.CreateElement("WesternAlliedFlak");
            WesternAlliedFlakNode.InnerText = WesternAlliedFlak.ToString();
            nodeToReturn.AppendChild(WesternAlliedFlakNode);

            System.Xml.XmlNode OriginalGermanBombersNode = xml.CreateElement("OriginalGermanBombers");
            OriginalGermanBombersNode.InnerText = originalGermanBombers.ToString();
            nodeToReturn.AppendChild(OriginalGermanBombersNode);

            System.Xml.XmlNode OriginalGermanFightersNode = xml.CreateElement("OriginalGermanFighters");
            OriginalGermanFightersNode.InnerText = originalGermanFighters.ToString();
            nodeToReturn.AppendChild(OriginalGermanFightersNode);

            System.Xml.XmlNode GermanFlakNode = xml.CreateElement("GermanFlak");
            GermanFlakNode.InnerText = GermanFlak.ToString();
            nodeToReturn.AppendChild(GermanFlakNode);

            System.Xml.XmlNode TargetedWERPProductionNode = xml.CreateElement("TargetedWERPProduction");
            TargetedWERPProductionNode.InnerText = targetedWERPProduction.ToString();
            nodeToReturn.AppendChild(TargetedWERPProductionNode);

            System.Xml.XmlNode CurrentWesternWeatherNode = xml.CreateElement("CurrentWesternWeather");
            CurrentWesternWeatherNode.InnerText = Enum.GetName(typeof(GameState.Weather), currentWesternWeather);
            nodeToReturn.AppendChild(CurrentWesternWeatherNode);

            System.Xml.XmlNode CurrentGameDateNode = xml.CreateElement("CurrentGameDate");
            CurrentGameDateNode.InnerText = Enum.GetName(typeof(GameTurn.GameDate), currentGameDate);
            nodeToReturn.AppendChild(CurrentGameDateNode);

            System.Xml.XmlNode CurrentGamePhaseNode = xml.CreateElement("CurrentGamePhase");
            CurrentGamePhaseNode.InnerText = Enum.GetName(typeof(GameTurn.GamePhase), currentGamePhase);
            nodeToReturn.AppendChild(CurrentGamePhaseNode);

            System.Xml.XmlNode UpgradedEscortsNode = xml.CreateElement("UpgradedEscorts");
            UpgradedEscortsNode.InnerText = upgradedEscorts.ToString();
            nodeToReturn.AppendChild(UpgradedEscortsNode);

            System.Xml.XmlNode UpgradeBombersNode = xml.CreateElement("UpgradeBombers");
            UpgradeBombersNode.InnerText = upgradeBombers.ToString();
            nodeToReturn.AppendChild(UpgradeBombersNode);

            System.Xml.XmlNode OperationOverlordNode = xml.CreateElement("OperationOverlord");
            OperationOverlordNode.InnerText = operationOverlord.ToString();
            nodeToReturn.AppendChild(OperationOverlordNode);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("NumEscortsShotDown");
            nodeToAdd.InnerText = numEscortsShotDown.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumInterceptorsShotDownByEscorts");
            nodeToAdd.InnerText = numInterceptorsShotDownByEscorts.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumInterceptorsShotDownByBombers");
            nodeToAdd.InnerText = numInterceptorsShotDownByBombers.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumBombersShotDownByInterceptors");
            nodeToAdd.InnerText = numBombersShotDownByInterceptors.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumBombersShotDownByFlak");
            nodeToAdd.InnerText = numBombersShotDownByFlak.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumStrategicBombHits");
            nodeToAdd.InnerText = numStrategicBombHits.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageReportStrategicBombingWarfare Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            uint originalWesternAlliedBombers = 0;
            uint originalWesternAlliedFighters = 0;
            uint WesternAlliedFlak = 0;
            uint originalGermanBombers = 0;
            uint originalGermanFighters = 0;
            uint GermanFlak = 0;
            uint targetedWERPProduction = 0;
            GameState.Weather currentWesternWeather = GameState.Weather.Clear;
            GameTurn.GameDate currentGameDate = GameTurn.GameDate.JanFeb40;
            GameTurn.GamePhase currentGamePhase = GameTurn.GamePhase.AlliedPlayerTurn;
            bool upgradedEscorts = false;
            bool upgradeBombers = false;
            bool operationOverlord = false;
            int numEscortsShotDown = 0;
            int numInterceptorsShotDownByEscorts = 0;
            int numInterceptorsShotDownByBombers = 0;
            int numBombersShotDownByInterceptors = 0;
            int numBombersShotDownByFlak = 0;
            int numStrategicBombHits = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "OriginalWesternAlliedBombers")
                    originalWesternAlliedBombers = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalWesternAlliedFighters")
                    originalWesternAlliedFighters = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "WesternAlliedFlak")
                    WesternAlliedFlak = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalGermanBombers")
                    originalGermanBombers = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "OriginalGermanFighters")
                    originalGermanFighters = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "GermanFlak")
                    GermanFlak = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "TargetedWERPProduction")
                    targetedWERPProduction = (uint)Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CurrentWesternWeather")
                    currentWesternWeather = (GameState.Weather)Enum.Parse(typeof(GameState.Weather), childNode.InnerText);
                if (childNode.Name == "CurrentGameDate")
                    currentGameDate = (GameTurn.GameDate)Enum.Parse(typeof(GameTurn.GameDate), childNode.InnerText);
                if (childNode.Name == "CurrentGamePhase")
                    currentGamePhase = (GameTurn.GamePhase)Enum.Parse(typeof(GameTurn.GamePhase), childNode.InnerText);
                if (childNode.Name == "UpgradedEscorts")
                    upgradedEscorts = bool.Parse(childNode.InnerText);
                if (childNode.Name == "UpgradeBombers")
                    upgradeBombers = bool.Parse(childNode.InnerText);
                if (childNode.Name == "OperationOverlord")
                    operationOverlord = bool.Parse(childNode.InnerText);
                if (childNode.Name == "NumEscortsShotDown")
                    numEscortsShotDown = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumInterceptorsShotDownByEscorts")
                    numInterceptorsShotDownByEscorts = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumInterceptorsShotDownByBombers")
                    numInterceptorsShotDownByBombers = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumBombersShotDownByInterceptors")
                    numBombersShotDownByInterceptors = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumBombersShotDownByFlak")
                    numBombersShotDownByFlak = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumStrategicBombHits")
                    numStrategicBombHits = Int32.Parse(childNode.InnerText);
            }

            return new ServerMessageReportStrategicBombingWarfare(player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers, operationOverlord, numEscortsShotDown, numInterceptorsShotDownByEscorts, numInterceptorsShotDownByBombers, numBombersShotDownByInterceptors, numBombersShotDownByFlak, numStrategicBombHits);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.ReportStrategicBombingWarfare(this.player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers, operationOverlord, numEscortsShotDown, numInterceptorsShotDownByEscorts, numInterceptorsShotDownByBombers, numBombersShotDownByInterceptors, numBombersShotDownByFlak, numStrategicBombHits);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDoStrategicUBoatWarfare : ServerMessagePlayerCall
    {
        private int numGermanUBoats;
        private int numBritishASWLevel;
        private int UKWERPProduction;

        public ServerMessageDoStrategicUBoatWarfare(int numGermanUBoats, int numBritishASWLevel, int UKWERPProduction)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoStrategicUBoatWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.DoStrategicUBoatWarfareReturn;

            this.numGermanUBoats = numGermanUBoats;
            this.numBritishASWLevel = numBritishASWLevel;
            this.UKWERPProduction = UKWERPProduction;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoStrategicUBoatWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode NumGermanUBoatsNode = xml.CreateElement("NumGermanUBoats");
            NumGermanUBoatsNode.InnerText = numGermanUBoats.ToString(); ;
            nodeToReturn.AppendChild(NumGermanUBoatsNode);

            System.Xml.XmlNode NumBritishASWLevelNode = xml.CreateElement("NumBritishASWLevel");
            NumBritishASWLevelNode.InnerText = numBritishASWLevel.ToString();
            nodeToReturn.AppendChild(NumBritishASWLevelNode);

            System.Xml.XmlNode UKWERPProductionNode = xml.CreateElement("UKWERPProduction");
            UKWERPProductionNode.InnerText = UKWERPProduction.ToString();
            nodeToReturn.AppendChild(UKWERPProductionNode);

            return nodeToReturn;
        }

        public new static ServerMessageDoStrategicUBoatWarfare Deserialise(System.Xml.XmlNode node)
        {
            int numGermanUBoats = 0;
            int numBritishASWLevel = 0;
            int UKWERPProduction = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "NumGermanUBoats")
                    numGermanUBoats = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumBritishASWLevel")
                    numBritishASWLevel = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "UKWERPProduction")
                    UKWERPProduction = Int32.Parse(childNode.InnerText);
            }

            return new ServerMessageDoStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            StratWarfareMove returnValue = player.DoStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction);
            return new ClientMessageDoStrategicUBoatWarfareReturn(returnValue);
        }
    };

    class ServerMessageReportStrategicUBoatWarfare : ServerMessagePlayerCall
    {
        private int numGermanUBoats;
        private int numBritishASWLevel;
        private int UKWERPProduction;
        private int numASWHits;
        private int numWERPHits;

        public ServerMessageReportStrategicUBoatWarfare(int numGermanUBoats, int numBritishASWLevel, int UKWERPProduction, int numASWHits, int numWERPHits)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.ReportStrategicUBoatWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;

            this.numGermanUBoats = numGermanUBoats;
            this.numBritishASWLevel = numBritishASWLevel;
            this.UKWERPProduction = UKWERPProduction;
            this.numASWHits = numASWHits;
            this.numWERPHits = numWERPHits;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageReportStrategicUBoatWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode NumGermanUBoatsNode = xml.CreateElement("NumGermanUBoats");
            NumGermanUBoatsNode.InnerText = numGermanUBoats.ToString(); ;
            nodeToReturn.AppendChild(NumGermanUBoatsNode);

            System.Xml.XmlNode NumBritishASWLevelNode = xml.CreateElement("NumBritishASWLevel");
            NumBritishASWLevelNode.InnerText = numBritishASWLevel.ToString();
            nodeToReturn.AppendChild(NumBritishASWLevelNode);

            System.Xml.XmlNode UKWERPProductionNode = xml.CreateElement("UKWERPProduction");
            UKWERPProductionNode.InnerText = UKWERPProduction.ToString();
            nodeToReturn.AppendChild(UKWERPProductionNode);

            System.Xml.XmlNode NumASWHitsNode = xml.CreateElement("NumASWHits");
            NumASWHitsNode.InnerText = numASWHits.ToString();
            nodeToReturn.AppendChild(NumASWHitsNode);

            System.Xml.XmlNode NumWERPHitsNode = xml.CreateElement("NumWERPHits");
            NumWERPHitsNode.InnerText = numWERPHits.ToString();
            nodeToReturn.AppendChild(NumWERPHitsNode);

            return nodeToReturn;
        }

        public new static ServerMessageReportStrategicUBoatWarfare Deserialise(System.Xml.XmlNode node)
        {
            int numGermanUBoats = 0;
            int numBritishASWLevel = 0;
            int UKWERPProduction = 0;
            int numASWHits = 0;
            int numWERPHits = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "NumGermanUBoats")
                    numGermanUBoats = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumBritishASWLevel")
                    numBritishASWLevel = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "UKWERPProduction")
                    UKWERPProduction = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumASWHits")
                    numASWHits = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumWERPHits")
                    numWERPHits = Int32.Parse(childNode.InnerText);
            }

            return new ServerMessageReportStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction, numASWHits, numWERPHits);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.ReportStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction, numASWHits, numWERPHits);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDoStrategicVWeaponWarfare : ServerMessagePlayerCall
    {
        private int numV1s;
        private int numV2s;
        private int numFigthers;
        private int flakLevel;
        private int WERPs;

        public ServerMessageDoStrategicVWeaponWarfare(int numV1s, int numV2s, int numFigthers, int flakLevel, int WERPs)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoStrategicVWeaponWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.StratWarfareReturn;

            this.numV1s = numV1s;
            this.numV2s = numV2s;
            this.numFigthers = numFigthers;
            this.flakLevel = flakLevel;
            this.WERPs = WERPs;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoStrategicVWeaponWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode NumV1sNode = xml.CreateElement("NumV1s");
            NumV1sNode.InnerText = numV1s.ToString(); ;
            nodeToReturn.AppendChild(NumV1sNode);

            System.Xml.XmlNode NumV2sNode = xml.CreateElement("NumV2s");
            NumV2sNode.InnerText = numV2s.ToString();
            nodeToReturn.AppendChild(NumV2sNode);

            System.Xml.XmlNode NumFigthersNode = xml.CreateElement("NumFigthers");
            NumFigthersNode.InnerText = numFigthers.ToString();
            nodeToReturn.AppendChild(NumFigthersNode);


            System.Xml.XmlNode FlakLevelNode = xml.CreateElement("FlakLevel");
            FlakLevelNode.InnerText = flakLevel.ToString();
            nodeToReturn.AppendChild(FlakLevelNode);

            System.Xml.XmlNode WERPsNode = xml.CreateElement("WERPs");
            WERPsNode.InnerText = WERPs.ToString();
            nodeToReturn.AppendChild(WERPsNode);

            return nodeToReturn;
        }

        public new static ServerMessageDoStrategicVWeaponWarfare Deserialise(System.Xml.XmlNode node)
        {
            int numV1s = 0;
            int numV2s = 0;
            int numFigthers = 0;
            int flakLevel = 0;
            int WERPs = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "NumV1s")
                    numV1s = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV2s")
                    numV2s = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumFigthers")
                    numFigthers = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "FlakLevel")
                    flakLevel = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "WERPs")
                    WERPs = Int32.Parse(childNode.InnerText);
            }

            return new ServerMessageDoStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<StratWarfareMove> returnValue = player.DoStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs);
            return new ClientMessageDoStrategicBombingWarfareReturn(returnValue);
        }
    };

    class ServerMessageReportStrategicVWeaponWarfare : ServerMessagePlayerCall
    {
        private int numV1s;
        private int numV2s;
        private int numFigthers;
        private int flakLevel;
        private int WERPs;
        private int numV1sLaunched;
        private int numV2sLaunched;
        private int NumV1sShotDownByFighters;
        private int NumV1sShotDownByFlak;
        private int numWERPsShotDownByV1s;
        private int numWERPsShotDownByV2s;

        public ServerMessageReportStrategicVWeaponWarfare(int numV1s, int numV2s, int numFigthers, int flakLevel, int WERPs, int numV1sLaunched, int numV2sLaunched, int NumV1sShotDownByFighters, int NumV1sShotDownByFlak, int numWERPsShotDownByV1s, int numWERPsShotDownByV2s)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.ReportStrategicVWeaponWarfare;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;

            this.numV1s = numV1s;
            this.numV2s = numV2s;
            this.numFigthers = numFigthers;
            this.flakLevel = flakLevel;
            this.WERPs = WERPs;
            this.numV1sLaunched = numV1sLaunched;
            this.numV2sLaunched = numV2sLaunched;
            this.NumV1sShotDownByFighters = NumV1sShotDownByFighters;
            this.NumV1sShotDownByFlak = NumV1sShotDownByFlak;
            this.numWERPsShotDownByV1s = numWERPsShotDownByV1s;
            this.numWERPsShotDownByV2s = numWERPsShotDownByV2s;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageReportStrategicVWeaponWarfare";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode NumV1sNode = xml.CreateElement("NumV1s");
            NumV1sNode.InnerText = numV1s.ToString(); ;
            nodeToReturn.AppendChild(NumV1sNode);

            System.Xml.XmlNode NumV2sNode = xml.CreateElement("NumV2s");
            NumV2sNode.InnerText = numV2s.ToString();
            nodeToReturn.AppendChild(NumV2sNode);

            System.Xml.XmlNode NumFigthersNode = xml.CreateElement("NumFigthers");
            NumFigthersNode.InnerText = numFigthers.ToString();
            nodeToReturn.AppendChild(NumFigthersNode);


            System.Xml.XmlNode FlakLevelNode = xml.CreateElement("FlakLevel");
            FlakLevelNode.InnerText = flakLevel.ToString();
            nodeToReturn.AppendChild(FlakLevelNode);

            System.Xml.XmlNode WERPsNode = xml.CreateElement("WERPs");
            WERPsNode.InnerText = WERPs.ToString();
            nodeToReturn.AppendChild(WERPsNode);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("NumV1sLaunched");
            nodeToAdd.InnerText = numV1sLaunched.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumV2sLaunched");
            nodeToAdd.InnerText = numV2sLaunched.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumV1sShotDownByFighters");
            nodeToAdd.InnerText = NumV1sShotDownByFighters.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumV1sShotDownByFlak");
            nodeToAdd.InnerText = NumV1sShotDownByFlak.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumWERPsShotDownByV1s");
            nodeToAdd.InnerText = numWERPsShotDownByV1s.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumWERPsShotDownByV2s");
            nodeToAdd.InnerText = numWERPsShotDownByV2s.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageReportStrategicVWeaponWarfare Deserialise(System.Xml.XmlNode node)
        {
            int numV1s = 0;
            int numV2s = 0;
            int numFigthers = 0;
            int flakLevel = 0;
            int WERPs = 0;
            int numV1sLaunched = 0;
            int numV2sLaunched = 0;
            int NumV1sShotDownByFighters = 0;
            int NumV1sShotDownByFlak = 0;
            int numWERPsShotDownByV1s = 0;
            int numWERPsShotDownByV2s = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "NumV1s")
                    numV1s = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV2s")
                    numV2s = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumFigthers")
                    numFigthers = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "FlakLevel")
                    flakLevel = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "WERPs")
                    WERPs = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV1sLaunched")
                    numV1sLaunched = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV2sLaunched")
                    numV2sLaunched = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV1sShotDownByFighters")
                    NumV1sShotDownByFighters = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumV1sShotDownByFlak")
                    NumV1sShotDownByFlak = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumWERPsShotDownByV1s")
                    numWERPsShotDownByV1s = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumWERPsShotDownByV2s")
                    numWERPsShotDownByV2s = Int32.Parse(childNode.InnerText);
            }

            return new ServerMessageReportStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs, numV1sLaunched, numV2sLaunched, NumV1sShotDownByFighters, NumV1sShotDownByFlak, numWERPsShotDownByV1s, numWERPsShotDownByV2s);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.ReportStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs, numV1sLaunched, numV2sLaunched, NumV1sShotDownByFighters, NumV1sShotDownByFlak, numWERPsShotDownByV1s, numWERPsShotDownByV2s);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDoAxisProductionPhase : ServerMessagePlayerCall
    {
        private Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources;
        private int germanInitialWERPS;
        private int ItalianInitialWERPS;
        private int strategicWarfareLosses;
        private int germanFleetMaintenance;
        private int italianFleetMaintenance;
        private int startingGermanSpecialActions;
        private int maxGermanSpecialActions;
        private int startingItalianSpecialActions;
        private int maxItalianSpecialActions;
        private bool germanFleetBuildAvailable;
        private bool italianFleetBuildAvailable;
        private bool FlakBuildable;
        private bool V1BuildAvailable;
        private bool V2BuildAvailable;
        private bool PloestiRestrictionsInEffect;
        private List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments;

        public ServerMessageDoAxisProductionPhase(Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources, int germanInitialWERPS, int ItalianInitialWERPS, int strategicWarfareLosses, int germanFleetMaintenance, int italianFleetMaintenance, int startingGermanSpecialActions, int maxGermanSpecialActions, int startingItalianSpecialActions, int maxItalianSpecialActions, bool germanFleetBuildAvailable, bool italianFleetBuildAvailable, bool FlakBuildable, bool V1BuildAvailable, bool V2BuildAvailable, bool PloestiRestrictionsInEffect, List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoAxisProductionPhase;
            serverMessageExpected = TCPServer.ServerRequestMessage.ProductionMovesReturn;

            if (countryValidSupplySources != null)
                this.countryValidSupplySources = new Dictionary<MapInfo.CountryID, List<Region>>(countryValidSupplySources);
            else
                this.countryValidSupplySources = new Dictionary<MapInfo.CountryID, List<Region>>();
            this.germanInitialWERPS = germanInitialWERPS;
            this.ItalianInitialWERPS = ItalianInitialWERPS;
            this.strategicWarfareLosses = strategicWarfareLosses;
            this.germanFleetMaintenance = germanFleetMaintenance;
            this.italianFleetMaintenance = italianFleetMaintenance;
            this.startingGermanSpecialActions = startingGermanSpecialActions;
            this.maxGermanSpecialActions = maxGermanSpecialActions;
            this.startingItalianSpecialActions = startingItalianSpecialActions;
            this.maxItalianSpecialActions = maxItalianSpecialActions;
            this.germanFleetBuildAvailable = germanFleetBuildAvailable;
            this.italianFleetBuildAvailable = italianFleetBuildAvailable;
            this.FlakBuildable = FlakBuildable;
            this.V1BuildAvailable = V1BuildAvailable;
            this.V2BuildAvailable = V2BuildAvailable;
            this.PloestiRestrictionsInEffect = PloestiRestrictionsInEffect;
            if (listOfForcePoolAdjustments != null)
                this.listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>(listOfForcePoolAdjustments);
            else
                this.listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoAxisProductionPhase";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode CountryValidSupplySourcesNode = xml.CreateElement("CountryValidSupplySources");
            foreach (MapInfo.CountryID country in countryValidSupplySources.Keys)
            {
                System.Xml.XmlNode ValidSupplySourcesNode = xml.CreateElement("ValidSupplySources");
                System.Xml.XmlAttribute countryTypeAttr = xml.CreateAttribute("Country");
                countryTypeAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                ValidSupplySourcesNode.Attributes.Append(countryTypeAttr);
                foreach (Region region in countryValidSupplySources[country])
                {
                    System.Xml.XmlNode RegionNode = xml.CreateElement("Region");
                    RegionNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), region.RegionID);
                    ValidSupplySourcesNode.AppendChild(RegionNode);
                }
                CountryValidSupplySourcesNode.AppendChild(ValidSupplySourcesNode);
            }
            nodeToReturn.AppendChild(CountryValidSupplySourcesNode);

            System.Xml.XmlNode GermanInitialWERPSNode = xml.CreateElement("GermanInitialWERPS");
            GermanInitialWERPSNode.InnerText = germanInitialWERPS.ToString();
            nodeToReturn.AppendChild(GermanInitialWERPSNode);

            System.Xml.XmlNode ItalianInitialWERPSNode = xml.CreateElement("ItalianInitialWERPS");
            ItalianInitialWERPSNode.InnerText = ItalianInitialWERPS.ToString();
            nodeToReturn.AppendChild(ItalianInitialWERPSNode);


            System.Xml.XmlNode StrategicWarfareLossesNode = xml.CreateElement("StrategicWarfareLosses");
            StrategicWarfareLossesNode.InnerText = strategicWarfareLosses.ToString();
            nodeToReturn.AppendChild(StrategicWarfareLossesNode);

            System.Xml.XmlNode GermanFleetMaintenanceNode = xml.CreateElement("GermanFleetMaintenance");
            GermanFleetMaintenanceNode.InnerText = germanFleetMaintenance.ToString();
            nodeToReturn.AppendChild(GermanFleetMaintenanceNode);

            System.Xml.XmlNode ItalianFleetMaintenanceNode = xml.CreateElement("ItalianFleetMaintenance");
            ItalianFleetMaintenanceNode.InnerText = italianFleetMaintenance.ToString();
            nodeToReturn.AppendChild(ItalianFleetMaintenanceNode);

            System.Xml.XmlNode StartingGermanSpecialActionsNode = xml.CreateElement("StartingGermanSpecialActions");
            StartingGermanSpecialActionsNode.InnerText = startingGermanSpecialActions.ToString();
            nodeToReturn.AppendChild(StartingGermanSpecialActionsNode);

            System.Xml.XmlNode MaxGermanSpecialActionsNode = xml.CreateElement("MaxGermanSpecialActions");
            MaxGermanSpecialActionsNode.InnerText = maxGermanSpecialActions.ToString();
            nodeToReturn.AppendChild(MaxGermanSpecialActionsNode);

            System.Xml.XmlNode StartingItalianSpecialActionsNode = xml.CreateElement("StartingItalianSpecialActions");
            StartingItalianSpecialActionsNode.InnerText = startingItalianSpecialActions.ToString();
            nodeToReturn.AppendChild(StartingItalianSpecialActionsNode);

            System.Xml.XmlNode MaxItalianSpecialActionsNode = xml.CreateElement("MaxItalianSpecialActions");
            MaxItalianSpecialActionsNode.InnerText = maxItalianSpecialActions.ToString();
            nodeToReturn.AppendChild(MaxItalianSpecialActionsNode);

            System.Xml.XmlNode GermanFleetBuildAvailableNode = xml.CreateElement("GermanFleetBuildAvailable");
            GermanFleetBuildAvailableNode.InnerText = germanFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(GermanFleetBuildAvailableNode);

            System.Xml.XmlNode ItalianFleetBuildAvailableNode = xml.CreateElement("ItalianFleetBuildAvailable");
            ItalianFleetBuildAvailableNode.InnerText = italianFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(ItalianFleetBuildAvailableNode);

            System.Xml.XmlNode FlakBuildableNode = xml.CreateElement("FlakBuildable");
            FlakBuildableNode.InnerText = FlakBuildable.ToString();
            nodeToReturn.AppendChild(FlakBuildableNode);

            System.Xml.XmlNode V1BuildAvailableNode = xml.CreateElement("V1BuildAvailable");
            V1BuildAvailableNode.InnerText = V1BuildAvailable.ToString();
            nodeToReturn.AppendChild(V1BuildAvailableNode);

            System.Xml.XmlNode V2BuildAvailableNode = xml.CreateElement("V2BuildAvailable");
            V2BuildAvailableNode.InnerText = V2BuildAvailable.ToString();
            nodeToReturn.AppendChild(V2BuildAvailableNode);

            System.Xml.XmlNode PloestiRestrictionsInEffectNode = xml.CreateElement("PloestiRestrictionsInEffect");
            PloestiRestrictionsInEffectNode.InnerText = PloestiRestrictionsInEffect.ToString();
            nodeToReturn.AppendChild(PloestiRestrictionsInEffectNode);

            System.Xml.XmlNode ListOfForcePoolAdjustmentsNode = xml.CreateElement("ListOfForcePoolAdjustments");
            foreach (GameState.ForcePoolAdjustment forcePoolAdjustment in listOfForcePoolAdjustments)
            {
                System.Xml.XmlNode ForcePoolAdjustmentNode = xml.CreateElement("ForcePoolAdjustment");
                System.Xml.XmlAttribute Attr = xml.CreateAttribute("GameDate");
                Attr.Value = Enum.GetName(typeof(GameTurn.GameDate), forcePoolAdjustment.gameDate);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);
                Attr = xml.CreateAttribute("Country");
                Attr.Value = Enum.GetName(typeof(MapInfo.CountryID), forcePoolAdjustment.country);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);
                Attr = xml.CreateAttribute("ForcePoolAjustmentType");
                Attr.Value = Enum.GetName(typeof(GameState.ForcePoolAjustmentType), forcePoolAdjustment.forcePoolAjustmentType);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);

                if(forcePoolAdjustment.blockToAdd != null)
                {
                    System.Xml.XmlNode BlockToAddNode = xml.CreateElement("BlockToAdd");
                    BlockToAddNode.AppendChild(forcePoolAdjustment.blockToAdd.Serialise(xml));
                    ForcePoolAdjustmentNode.AppendChild(BlockToAddNode);
                }
                ListOfForcePoolAdjustmentsNode.AppendChild(ForcePoolAdjustmentNode);
            }
            nodeToReturn.AppendChild(ListOfForcePoolAdjustmentsNode);

            return nodeToReturn;
        }

        public new static ServerMessageDoAxisProductionPhase Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources = new Dictionary<MapInfo.CountryID,List<Region>>();
            int germanInitialWERPS = 0;
            int ItalianInitialWERPS = 0;
            int strategicWarfareLosses = 0;
            int germanFleetMaintenance = 0;
            int italianFleetMaintenance = 0;
            int startingGermanSpecialActions = 0;
            int maxGermanSpecialActions = 0;
            int startingItalianSpecialActions = 0;
            int maxItalianSpecialActions = 0;
            bool germanFleetBuildAvailable = false;
            bool italianFleetBuildAvailable = false;
            bool FlakBuildable = false;
            bool V1BuildAvailable = false;
            bool V2BuildAvailable = false;
            bool PloestiRestrictionsInEffect = false;
            List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch(childNode.Name)
                {
                    case "CountryValidSupplySources":
                        foreach (System.Xml.XmlNode ValidSupplySourcesNode in childNode)
                        {
                            MapInfo.CountryID country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), ValidSupplySourcesNode.Attributes["Country"].Value);
                            countryValidSupplySources.Add(country, new List<Region>());
                            foreach (System.Xml.XmlNode RegionNode in ValidSupplySourcesNode)
                            {
                                if(RegionNode.Name == "Region")
                                {
                                    countryValidSupplySources[country].Add(MapInfo.GetRegion((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), RegionNode.InnerText)));
                                }
                            }
                        }
                        break;
                    case "GermanInitialWERPS":
                        germanInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "ItalianInitialWERPS":
                        ItalianInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "StrategicWarfareLosses":
                        strategicWarfareLosses = Int32.Parse(childNode.InnerText);
                        break;
                    case "GermanFleetMaintenance":
                        germanFleetMaintenance = Int32.Parse(childNode.InnerText);
                        break;
                    case "ItalianFleetMaintenance":
                        italianFleetMaintenance = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingGermanSpecialActions":
                        startingGermanSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "MaxGermanSpecialActions":
                        maxGermanSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingItalianSpecialActions":
                        startingItalianSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "MaxItalianSpecialActions":
                        maxItalianSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "GermanFleetBuildAvailable":
                        germanFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "ItalianFleetBuildAvailable":
                        italianFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "FlakBuildable":
                        FlakBuildable = bool.Parse(childNode.InnerText);
                        break;
                    case "V1BuildAvailable":
                        V1BuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "V2BuildAvailable":
                        V2BuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "PloestiRestrictionsInEffect":
                        PloestiRestrictionsInEffect = bool.Parse(childNode.InnerText);
                        break;
                    case "ListOfForcePoolAdjustments":
                        {
                            foreach(System.Xml.XmlNode ForcePoolAdjustmentNode in childNode)
                            {
                                GameTurn.GameDate gamDate = (GameTurn.GameDate)Enum.Parse(typeof(GameTurn.GameDate), ForcePoolAdjustmentNode.Attributes["GameDate"].Value);
                                MapInfo.CountryID country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), ForcePoolAdjustmentNode.Attributes["Country"].Value);
                                GameState.ForcePoolAjustmentType forcePoolAdjustmentType = (GameState.ForcePoolAjustmentType)Enum.Parse(typeof(GameState.ForcePoolAjustmentType), ForcePoolAdjustmentNode.Attributes["ForcePoolAjustmentType"].Value);
                                Block block = null;
                                if(ForcePoolAdjustmentNode.ChildNodes.Count > 0)
                                {
                                    if(ForcePoolAdjustmentNode.ChildNodes[0].Name == "BlockToAdd")
                                    {
                                        block = Block.Deserialise(ForcePoolAdjustmentNode.ChildNodes[0].FirstChild);
                                    }
                                }
                                listOfForcePoolAdjustments.Add(new GameState.ForcePoolAdjustment(gamDate, country, forcePoolAdjustmentType, block));
                            }
                        }
                        break;
                }
            }

            return new ServerMessageDoAxisProductionPhase(countryValidSupplySources, germanInitialWERPS, ItalianInitialWERPS, strategicWarfareLosses, germanFleetMaintenance, italianFleetMaintenance, startingGermanSpecialActions, maxGermanSpecialActions, startingItalianSpecialActions, maxItalianSpecialActions, germanFleetBuildAvailable, italianFleetBuildAvailable, FlakBuildable, V1BuildAvailable, V2BuildAvailable, PloestiRestrictionsInEffect, listOfForcePoolAdjustments);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<ProductionMove> returnValue = player.DoAxisProductionPhase(countryValidSupplySources, germanInitialWERPS, ItalianInitialWERPS, strategicWarfareLosses, germanFleetMaintenance, italianFleetMaintenance, startingGermanSpecialActions, maxGermanSpecialActions, startingItalianSpecialActions, maxItalianSpecialActions, germanFleetBuildAvailable, italianFleetBuildAvailable, FlakBuildable, V1BuildAvailable, V2BuildAvailable, PloestiRestrictionsInEffect, listOfForcePoolAdjustments);
            return new ClientMessageProductionMovesReturn(returnValue);
        }
    };

    class ServerMessageDoAlliedProductionPhase : ServerMessagePlayerCall
    {
        private Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources;
        private int UKInitialWERPS;
        private int frenchInitialWERPS;
        private int USSRInitialWERPS;
        private int USAInitialWERPS;
        private int strategicWarfareLosses;
        private int UKFleetMaintenance;
        private int frenchFleetMaintenance;
        private int USSRFleetMaintenance;
        private int startingUKSpecialActions;
        private int startingFrenchSpecialActions;
        private int startingUSSRSpecialActions;
        private int maxUSSRSpecialActions;
        private int startingUSASpecialActions;
        private int maxUSASpecialActions;
        private bool UKFleetBuildAvailable;
        private bool frenchFleetBuildAvailable;
        private bool USAFleetBuildAvailable;
        private bool USSRFleetBuildAvailable;
        private bool FlakBuildable;
        private bool ASWBuildAvailable;
        private bool USAtWar;
        private bool USSRAtWar;
        private int lendLeaseFromUSAForUK;
        private int lendLeaseFromUSAForUSSR;
        private int maxBritishWERPsToUSSR;
        private bool britishLendLeaseToUSSRHalved;
        private int russianEmergencyConscriptionSteps;
        private bool russianCadreBonusInEffect;
        private bool russianProductionPenalty;
        private bool britishProductionPenalty;
        private bool russianEliteInfantryReinforcements;
        private List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments;
        private GameController.UKLendLease ukLendLease;

        public ServerMessageDoAlliedProductionPhase(Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources, int UKInitialWERPS, int frenchInitialWERPS, int USSRInitialWERPS, int USAInitialWERPS, int strategicWarfareLosses, int UKFleetMaintenance, int frenchFleetMaintenance, int USSRFleetMaintenance, int startingUKSpecialActions, int startingFrenchSpecialActions, int startingUSSRSpecialActions, int maxUSSRSpecialActions, int startingUSASpecialActions, int maxUSASpecialActions, bool UKFleetBuildAvailable, bool frenchFleetBuildAvailable, bool USAFleetBuildAvailable, bool USSRFleetBuildAvailable, bool FlakBuildable, bool ASWBuildAvailable, bool USAtWar, bool USSRAtWar, int lendLeaseFromUSAForUK, int lendLeaseFromUSAForUSSR, int maxBritishWERPsToUSSR, bool britishLendLeaseToUSSRHalved, int russianEmergencyConscriptionSteps, bool russianCadreBonusInEffect, bool russianProductionPenalty, bool britishProductionPenalty, bool russianEliteInfantryReinforcements, List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments, GameController.UKLendLease ukLendLease)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoAlliedProductionPhase;
            serverMessageExpected = TCPServer.ServerRequestMessage.ProductionMovesReturn;

            if (countryValidSupplySources != null)
                this.countryValidSupplySources = new Dictionary<MapInfo.CountryID, List<Region>>(countryValidSupplySources);
            else
                this.countryValidSupplySources = new Dictionary<MapInfo.CountryID, List<Region>>();
            this.UKInitialWERPS = UKInitialWERPS;
            this.frenchInitialWERPS = frenchInitialWERPS;
            this.USSRInitialWERPS = USSRInitialWERPS;
            this.USAInitialWERPS = USAInitialWERPS;
            this.strategicWarfareLosses = strategicWarfareLosses;
            this.UKFleetMaintenance = UKFleetMaintenance;
            this.frenchFleetMaintenance = frenchFleetMaintenance;
            this.USSRFleetMaintenance = USSRFleetMaintenance;
            this.startingUKSpecialActions = startingUKSpecialActions;
            this.startingFrenchSpecialActions = startingFrenchSpecialActions;
            this.startingUSSRSpecialActions = startingUSSRSpecialActions;
            this.maxUSSRSpecialActions = maxUSSRSpecialActions;
            this.startingUSASpecialActions = startingUSASpecialActions;
            this.maxUSASpecialActions = maxUSASpecialActions;
            this.UKFleetBuildAvailable = UKFleetBuildAvailable;
            this.frenchFleetBuildAvailable = frenchFleetBuildAvailable;
            this.USAFleetBuildAvailable = USAFleetBuildAvailable;
            this.USSRFleetBuildAvailable = USSRFleetBuildAvailable;
            this.FlakBuildable = FlakBuildable;
            this.ASWBuildAvailable = ASWBuildAvailable;
            this.USAtWar = USAtWar;
            this.USSRAtWar = USSRAtWar;
            this.lendLeaseFromUSAForUK = lendLeaseFromUSAForUK;
            this.lendLeaseFromUSAForUSSR = lendLeaseFromUSAForUSSR;
            this.maxBritishWERPsToUSSR = maxBritishWERPsToUSSR;
            this.britishLendLeaseToUSSRHalved = britishLendLeaseToUSSRHalved;
            this.russianEmergencyConscriptionSteps = russianEmergencyConscriptionSteps;
            this.russianCadreBonusInEffect = russianCadreBonusInEffect;
            this.russianProductionPenalty = russianProductionPenalty;
            this.britishProductionPenalty = britishProductionPenalty;
            this.russianEliteInfantryReinforcements = russianEliteInfantryReinforcements;
            if (listOfForcePoolAdjustments != null)
                this.listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>(listOfForcePoolAdjustments);
            else
                this.listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>();
            this.ukLendLease = ukLendLease;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoAlliedProductionPhase";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode CountryValidSupplySourcesNode = xml.CreateElement("CountryValidSupplySources");
            foreach (MapInfo.CountryID country in countryValidSupplySources.Keys)
            {
                System.Xml.XmlNode ValidSupplySourcesNode = xml.CreateElement("ValidSupplySources");
                System.Xml.XmlAttribute countryTypeAttr = xml.CreateAttribute("Country");
                countryTypeAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                ValidSupplySourcesNode.Attributes.Append(countryTypeAttr);
                foreach (Region region in countryValidSupplySources[country])
                {
                    System.Xml.XmlNode RegionNode = xml.CreateElement("Region");
                    RegionNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), region.RegionID);
                    ValidSupplySourcesNode.AppendChild(RegionNode);
                }
                CountryValidSupplySourcesNode.AppendChild(ValidSupplySourcesNode);
            }
            nodeToReturn.AppendChild(CountryValidSupplySourcesNode);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("UKInitialWERPS");
            nodeToAdd.InnerText = UKInitialWERPS.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("FrenchInitialWERPS");
            nodeToAdd.InnerText = frenchInitialWERPS.ToString();
            nodeToReturn.AppendChild(nodeToAdd);


            nodeToAdd = xml.CreateElement("USSRInitialWERPS");
            nodeToAdd.InnerText = USSRInitialWERPS.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USAInitialWERPS");
            nodeToAdd.InnerText = USAInitialWERPS.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("StrategicWarfareLosses");
            nodeToAdd.InnerText = strategicWarfareLosses.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("UKFleetMaintenance");
            nodeToAdd.InnerText = UKFleetMaintenance.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("FrenchFleetMaintenance");
            nodeToAdd.InnerText = frenchFleetMaintenance.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USSRFleetMaintenance");
            nodeToAdd.InnerText = USSRFleetMaintenance.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("StartingUKSpecialActions");
            nodeToAdd.InnerText = startingUKSpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("StartingFrenchSpecialActions");
            nodeToAdd.InnerText = startingFrenchSpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("StartingUSSRSpecialActions");
            nodeToAdd.InnerText = startingUSSRSpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("MaxUSSRSpecialActions");
            nodeToAdd.InnerText = maxUSSRSpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("StartingUSASpecialActions");
            nodeToAdd.InnerText = startingUSASpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("MaxUSASpecialActions");
            nodeToAdd.InnerText = maxUSASpecialActions.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("UKFleetBuildAvailable");
            nodeToAdd.InnerText = UKFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("FrenchFleetBuildAvailable");
            nodeToAdd.InnerText = frenchFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USAFleetBuildAvailable");
            nodeToAdd.InnerText = USAFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USSRFleetBuildAvailable");
            nodeToAdd.InnerText = USSRFleetBuildAvailable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("FlakBuildable");
            nodeToAdd.InnerText = FlakBuildable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("ASWBuildAvailable");
            nodeToAdd.InnerText = ASWBuildAvailable.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USAtWar");
            nodeToAdd.InnerText = USAtWar.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("USSRAtWar");
            nodeToAdd.InnerText = USSRAtWar.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("LendLeaseFromUSAForUK");
            nodeToAdd.InnerText = lendLeaseFromUSAForUK.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("LendLeaseFromUSAForUSSR");
            nodeToAdd.InnerText = lendLeaseFromUSAForUSSR.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("MaxBritishWERPsToUSSR");
            nodeToAdd.InnerText = maxBritishWERPsToUSSR.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("BritishLendLeaseToUSSRHalved");
            nodeToAdd.InnerText = britishLendLeaseToUSSRHalved.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RussianEmergencyConscriptionSteps");
            nodeToAdd.InnerText = russianEmergencyConscriptionSteps.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RussianCadreBonusInEffect");
            nodeToAdd.InnerText = russianCadreBonusInEffect.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RussianProductionPenalty");
            nodeToAdd.InnerText = russianProductionPenalty.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("BritishProductionPenalty");
            nodeToAdd.InnerText = britishProductionPenalty.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RussianEliteInfantryReinforcements");
            nodeToAdd.InnerText = russianEliteInfantryReinforcements.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            System.Xml.XmlNode ListOfForcePoolAdjustmentsNode = xml.CreateElement("ListOfForcePoolAdjustments");
            foreach (GameState.ForcePoolAdjustment forcePoolAdjustment in listOfForcePoolAdjustments)
            {
                System.Xml.XmlNode ForcePoolAdjustmentNode = xml.CreateElement("ForcePoolAdjustment");
                System.Xml.XmlAttribute Attr = xml.CreateAttribute("GameDate");
                Attr.Value = Enum.GetName(typeof(GameTurn.GameDate), forcePoolAdjustment.gameDate);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);
                Attr = xml.CreateAttribute("Country");
                Attr.Value = Enum.GetName(typeof(MapInfo.CountryID), forcePoolAdjustment.country);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);
                Attr = xml.CreateAttribute("ForcePoolAjustmentType");
                Attr.Value = Enum.GetName(typeof(GameState.ForcePoolAjustmentType), forcePoolAdjustment.forcePoolAjustmentType);
                ForcePoolAdjustmentNode.Attributes.Append(Attr);

                if (forcePoolAdjustment.blockToAdd != null)
                {
                    System.Xml.XmlNode BlockToAddNode = xml.CreateElement("BlockToAdd");
                    BlockToAddNode.AppendChild(forcePoolAdjustment.blockToAdd.Serialise(xml));
                    ForcePoolAdjustmentNode.AppendChild(BlockToAddNode);
                }
                ListOfForcePoolAdjustmentsNode.AppendChild(ForcePoolAdjustmentNode);
            }
            nodeToReturn.AppendChild(ListOfForcePoolAdjustmentsNode);

            nodeToAdd = xml.CreateElement("UkLendLease");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.UKLendLease), ukLendLease);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoAlliedProductionPhase Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources = new Dictionary<MapInfo.CountryID,List<Region>>();
            int UKInitialWERPS = 0;
            int frenchInitialWERPS = 0;
            int USSRInitialWERPS = 0;
            int USAInitialWERPS = 0;
            int strategicWarfareLosses = 0;
            int UKFleetMaintenance = 0;
            int frenchFleetMaintenance = 0;
            int USSRFleetMaintenance = 0;
            int startingUKSpecialActions = 0;
            int startingFrenchSpecialActions = 0;
            int startingUSSRSpecialActions = 0;
            int maxUSSRSpecialActions = 0;
            int startingUSASpecialActions = 0;
            int maxUSASpecialActions = 0;
            bool UKFleetBuildAvailable = false;
            bool frenchFleetBuildAvailable = false;
            bool USAFleetBuildAvailable = false;
            bool USSRFleetBuildAvailable = false;
            bool FlakBuildable = false;
            bool ASWBuildAvailable = false;
            bool USAtWar = false;
            bool USSRAtWar = false;
            int lendLeaseFromUSAForUK = 0;
            int lendLeaseFromUSAForUSSR = 0;
            int maxBritishWERPsToUSSR = 0;
            bool britishLendLeaseToUSSRHalved = false;
            int russianEmergencyConscriptionSteps = 0;
            bool russianCadreBonusInEffect = false;
            bool russianProductionPenalty = false;
            bool britishProductionPenalty = false;
            bool russianEliteInfantryReinforcements = false;
            List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments = new List<GameState.ForcePoolAdjustment>();
            GameController.UKLendLease ukLendLease = GameController.UKLendLease.Murmansk;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "CountryValidSupplySources":
                        foreach (System.Xml.XmlNode ValidSupplySourcesNode in childNode)
                        {
                            MapInfo.CountryID country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), ValidSupplySourcesNode.Attributes["Country"].Value);
                            countryValidSupplySources.Add(country, new List<Region>());
                            foreach (System.Xml.XmlNode RegionNode in ValidSupplySourcesNode)
                            {
                                if (RegionNode.Name == "Region")
                                {
                                    countryValidSupplySources[country].Add(MapInfo.GetRegion((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), RegionNode.InnerText)));
                                }
                            }
                        }
                        break;
                    case "UKInitialWERPS":
                        UKInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "FrenchInitialWERPS":
                        frenchInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "USSRInitialWERPS":
                        USSRInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "USAInitialWERPS":
                        USAInitialWERPS = Int32.Parse(childNode.InnerText);
                        break;
                    case "StrategicWarfareLosses":
                        strategicWarfareLosses = Int32.Parse(childNode.InnerText);
                        break;
                    case "UKFleetMaintenance":
                        UKFleetMaintenance = Int32.Parse(childNode.InnerText);
                        break;
                    case "FrenchFleetMaintenance":
                        frenchFleetMaintenance = Int32.Parse(childNode.InnerText);
                        break;
                    case "USSRFleetMaintenance":
                        USSRFleetMaintenance = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingUKSpecialActions":
                        startingUKSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingFrenchSpecialActions":
                        startingFrenchSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingUSSRSpecialActions":
                        startingUSSRSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "MaxUSSRSpecialActions":
                        maxUSSRSpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "StartingUSASpecialActions":
                        startingUSASpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "MaxUSASpecialActions":
                        maxUSASpecialActions = Int32.Parse(childNode.InnerText);
                        break;
                    case "UKFleetBuildAvailable":
                        UKFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "FrenchFleetBuildAvailable":
                        frenchFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "USAFleetBuildAvailable":
                        USAFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "USSRFleetBuildAvailable":
                        USSRFleetBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "FlakBuildable":
                        FlakBuildable = bool.Parse(childNode.InnerText);
                        break;
                    case "ASWBuildAvailable":
                        ASWBuildAvailable = bool.Parse(childNode.InnerText);
                        break;
                    case "USAtWar":
                        USAtWar = bool.Parse(childNode.InnerText);
                        break;
                    case "USSRAtWar":
                        USSRAtWar = bool.Parse(childNode.InnerText);
                        break;
                    case "LendLeaseFromUSAForUK":
                        lendLeaseFromUSAForUK = Int32.Parse(childNode.InnerText);
                        break;
                    case "LendLeaseFromUSAForUSSR":
                        lendLeaseFromUSAForUSSR = Int32.Parse(childNode.InnerText);
                        break;
                    case "MaxBritishWERPsToUSSR":
                        maxBritishWERPsToUSSR = Int32.Parse(childNode.InnerText);
                        break;
                    case "BritishLendLeaseToUSSRHalved":
                        britishLendLeaseToUSSRHalved = bool.Parse(childNode.InnerText);
                        break;
                    case "RussianEmergencyConscriptionSteps":
                        russianEmergencyConscriptionSteps = Int32.Parse(childNode.InnerText);
                        break;
                    case "RussianCadreBonusInEffect":
                        russianCadreBonusInEffect = bool.Parse(childNode.InnerText);
                        break;
                    case "RussianProductionPenalty":
                        russianProductionPenalty = bool.Parse(childNode.InnerText);
                        break;
                    case "BritishProductionPenalty":
                        britishProductionPenalty = bool.Parse(childNode.InnerText);
                        break;
                    case "RussianEliteInfantryReinforcements":
                        russianEliteInfantryReinforcements = bool.Parse(childNode.InnerText);
                        break;
                    case "ListOfForcePoolAdjustments":
                        {
                            foreach (System.Xml.XmlNode ForcePoolAdjustmentNode in childNode)
                            {
                                GameTurn.GameDate gamDate = (GameTurn.GameDate)Enum.Parse(typeof(GameTurn.GameDate), ForcePoolAdjustmentNode.Attributes["GameDate"].Value);
                                MapInfo.CountryID country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), ForcePoolAdjustmentNode.Attributes["Country"].Value);
                                GameState.ForcePoolAjustmentType forcePoolAdjustmentType = (GameState.ForcePoolAjustmentType)Enum.Parse(typeof(GameState.ForcePoolAjustmentType), ForcePoolAdjustmentNode.Attributes["ForcePoolAjustmentType"].Value);
                                Block block = null;
                                if (ForcePoolAdjustmentNode.ChildNodes.Count > 0)
                                {
                                    if (ForcePoolAdjustmentNode.ChildNodes[0].Name == "BlockToAdd")
                                    {
                                        block = Block.Deserialise(ForcePoolAdjustmentNode.ChildNodes[0].FirstChild);
                                    }
                                }
                                listOfForcePoolAdjustments.Add(new GameState.ForcePoolAdjustment(gamDate, country, forcePoolAdjustmentType, block));
                            }
                        }
                        break;
                    case "UkLendLease":
                        ukLendLease = (GameController.UKLendLease)Enum.Parse(typeof(GameController.UKLendLease), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoAlliedProductionPhase(countryValidSupplySources, UKInitialWERPS, frenchInitialWERPS, USSRInitialWERPS, USAInitialWERPS, strategicWarfareLosses, UKFleetMaintenance, frenchFleetMaintenance, USSRFleetMaintenance, startingUKSpecialActions, startingFrenchSpecialActions, startingUSSRSpecialActions, maxUSSRSpecialActions, startingUSASpecialActions, maxUSASpecialActions, UKFleetBuildAvailable, frenchFleetBuildAvailable, USAFleetBuildAvailable, USSRFleetBuildAvailable, FlakBuildable, ASWBuildAvailable, USAtWar, USSRAtWar, lendLeaseFromUSAForUK, lendLeaseFromUSAForUSSR, maxBritishWERPsToUSSR, britishLendLeaseToUSSRHalved, russianEmergencyConscriptionSteps, russianCadreBonusInEffect, russianProductionPenalty, britishProductionPenalty, russianEliteInfantryReinforcements, listOfForcePoolAdjustments, ukLendLease);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<ProductionMove> returnValue = player.DoAlliedProductionPhase(countryValidSupplySources, UKInitialWERPS, frenchInitialWERPS, USSRInitialWERPS, USAInitialWERPS, strategicWarfareLosses, UKFleetMaintenance, frenchFleetMaintenance, USSRFleetMaintenance, startingUKSpecialActions, startingFrenchSpecialActions, startingUSSRSpecialActions, maxUSSRSpecialActions, startingUSASpecialActions, maxUSASpecialActions, UKFleetBuildAvailable, frenchFleetBuildAvailable, USAFleetBuildAvailable, USSRFleetBuildAvailable, FlakBuildable, ASWBuildAvailable, USAtWar, USSRAtWar, lendLeaseFromUSAForUK, lendLeaseFromUSAForUSSR, maxBritishWERPsToUSSR, britishLendLeaseToUSSRHalved, russianEmergencyConscriptionSteps, russianCadreBonusInEffect, russianProductionPenalty, britishProductionPenalty, russianEliteInfantryReinforcements, listOfForcePoolAdjustments, ukLendLease);
            return new ClientMessageProductionMovesReturn(returnValue);
        }
    };

    class ServerMessageAskForStrategicWarfareInterception : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageAskForStrategicWarfareInterception(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForStrategicWarfareInterception;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForStrategicWarfareInterception";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskForStrategicWarfareInterception Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
            }

            return new ServerMessageAskForStrategicWarfareInterception(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.AskForStrategicWarfareInterception(this.player);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDoSupplySelection : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private bool finalSupply;
        private Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSeaToReturn;
        private Dictionary<MapInfo.RegionID, int> seaSupplyPoints;

        public ServerMessageDoSupplySelection(GameController.playerType player, bool finalSupply, Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSeaToReturn, Dictionary<MapInfo.RegionID, int> seaSupplyPoints)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoSupplySelection;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
            this.finalSupply = finalSupply;
            if (regionsCountryOOSorUSingSeaToReturn != null)
                this.regionsCountryOOSorUSingSeaToReturn = new Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>>(regionsCountryOOSorUSingSeaToReturn);
            else
                this.regionsCountryOOSorUSingSeaToReturn = new Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>>();
            if (seaSupplyPoints != null)
                this.seaSupplyPoints = new Dictionary<MapInfo.RegionID, int>(seaSupplyPoints);
            else
                this.seaSupplyPoints = new Dictionary<MapInfo.RegionID, int>();

        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoSupplySelection";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("FinalSupply");
            nodeToAdd.InnerText = finalSupply.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionsCountryOOSorUSingSeaToReturn");
            foreach(MapInfo.RegionID regionID in regionsCountryOOSorUSingSeaToReturn.Keys)
            {
                System.Xml.XmlNode regionIDNode = xml.CreateElement("Region");
                System.Xml.XmlAttribute regionIDAttr = xml.CreateAttribute("RegionID");
                regionIDAttr.Value = Enum.GetName(typeof(MapInfo.RegionID), regionID);
                regionIDNode.Attributes.Append(regionIDAttr);
                foreach(MapInfo.CountryID country in regionsCountryOOSorUSingSeaToReturn[regionID].Keys)
                {
                    System.Xml.XmlNode countryIDNode = xml.CreateElement("Country");
                    System.Xml.XmlAttribute countryIDAttr = xml.CreateAttribute("CountryID");
                    countryIDAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                    countryIDNode.Attributes.Append(countryIDAttr);
                    foreach(GameController.SeaSupplySolution seaSupplySolution in regionsCountryOOSorUSingSeaToReturn[regionID][country])
                    {
                        System.Xml.XmlNode SeaSupplySolutionNode = xml.CreateElement("SeaSupplySolution");
                        System.Xml.XmlAttribute fromBeachHeadAttr = xml.CreateAttribute("FromBeachHead");
                        fromBeachHeadAttr.Value = seaSupplySolution.fromBeachHead.ToString();
                        SeaSupplySolutionNode.Attributes.Append(fromBeachHeadAttr);

                        foreach(SeaRegion seaRegion in seaSupplySolution.seaRegionPath)
                        {
                            System.Xml.XmlNode SeaRegionNode = xml.CreateElement("SeaRegion");
                            SeaRegionNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), seaRegion.RegionID);
                            SeaSupplySolutionNode.AppendChild(SeaRegionNode);
                        }

                        countryIDNode.AppendChild(SeaSupplySolutionNode);
                    }

                    regionIDNode.AppendChild(countryIDNode);
                }

                nodeToAdd.AppendChild(regionIDNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("SeaSupplyPoints");
            foreach (MapInfo.RegionID regionID in seaSupplyPoints.Keys)
            {
                System.Xml.XmlNode SeaSupplyPointsRegionNode = xml.CreateElement("SeaSupplyPointsRegion");
                System.Xml.XmlAttribute regionIDAttr = xml.CreateAttribute("RegionID");
                System.Xml.XmlAttribute supplyPointsAttr = xml.CreateAttribute("SupplyPoints");
                regionIDAttr.Value = Enum.GetName(typeof(MapInfo.RegionID), regionID);
                supplyPointsAttr.Value = seaSupplyPoints[regionID].ToString();
                SeaSupplyPointsRegionNode.Attributes.Append(regionIDAttr);
                SeaSupplyPointsRegionNode.Attributes.Append(supplyPointsAttr);
                nodeToAdd.AppendChild(SeaSupplyPointsRegionNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoSupplySelection Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            bool finalSupply = false;
            Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSeaToReturn = new Dictionary<MapInfo.RegionID,Dictionary<MapInfo.CountryID,List<GameController.SeaSupplySolution>>>();
            Dictionary<MapInfo.RegionID, int> seaSupplyPoints = new Dictionary<MapInfo.RegionID,int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch(childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "FinalSupply":
                        finalSupply = bool.Parse(childNode.InnerText);
                        break;
                    case "RegionsCountryOOSorUSingSeaToReturn":
                        foreach (System.Xml.XmlNode regionNode in childNode)
                        {
                            MapInfo.RegionID regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), regionNode.Attributes["RegionID"].Value);
                            regionsCountryOOSorUSingSeaToReturn.Add(regionID, new Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>());
                            foreach (System.Xml.XmlNode countryNode in regionNode)
                            {
                                MapInfo.CountryID countryID = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.Attributes["CountryID"].Value);
                                regionsCountryOOSorUSingSeaToReturn[regionID].Add(countryID, new List<GameController.SeaSupplySolution>());
                                foreach(System.Xml.XmlNode SeaSupplySolutionNode in countryNode)
                                {
                                    if(SeaSupplySolutionNode.Name == "SeaSupplySolution")
                                    {
                                        GameController.SeaSupplySolution seaSupplySolution = new GameController.SeaSupplySolution();
                                        seaSupplySolution.fromBeachHead = bool.Parse(SeaSupplySolutionNode.Attributes["FromBeachHead"].Value);
                                        seaSupplySolution.seaRegionPath = new List<SeaRegion>();
                                        foreach (System.Xml.XmlNode SeaRegionNode in SeaSupplySolutionNode)
                                        {
                                            if(SeaRegionNode.Name == "SeaRegion")
                                            {
                                                seaSupplySolution.seaRegionPath.Add((SeaRegion)MapInfo.GetRegion((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), SeaRegionNode.InnerText)));
                                            }
                                        }
                                        regionsCountryOOSorUSingSeaToReturn[regionID][countryID].Add(seaSupplySolution);
                                    }

                                }
                            }
                        }
                        break;
                    case "SeaSupplyPoints":
                        foreach (System.Xml.XmlNode SeaSupplyPointsRegionNode in childNode)
                        {
                            seaSupplyPoints.Add((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), SeaSupplyPointsRegionNode.Attributes["RegionID"].Value), Int32.Parse(SeaSupplyPointsRegionNode.Attributes["SupplyPoints"].Value));
                        }
                        break;
                }
            }

            return new ServerMessageDoSupplySelection(player, finalSupply, regionsCountryOOSorUSingSeaToReturn, seaSupplyPoints);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<SupplySelectionMove> returnValue = player.DoSupplySelection(this.player, finalSupply, regionsCountryOOSorUSingSeaToReturn, seaSupplyPoints);
            List<Move> listOfMoves = new List<Move>();
            foreach (SupplySelectionMove supplyMove in returnValue)
            {
                listOfMoves.Add(supplyMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoInitialOps : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDoInitialOps(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoInitialOps;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoInitialOps";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoInitialOps Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoInitialOps(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<OperationalMove> returnValue = player.DoInitialOps(this.player);
            List<Move> listOfMoves = new List<Move>();
            foreach (OperationalMove opMove in returnValue)
            {
                listOfMoves.Add(opMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoBreakThroughOps : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private List<MapInfo.CountryID> countriesSpendingSA;

        public ServerMessageDoBreakThroughOps(GameController.playerType player, List<MapInfo.CountryID> countriesSpendingSA)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoBreakThroughOps;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;

            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoBreakThroughOps";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            System.Xml.XmlNode CountriesSpendingSANode = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSANode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSANode);

            return nodeToReturn;
        }

        public new static ServerMessageDoBreakThroughOps Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "CountriesSpendingSA":
                        foreach (System.Xml.XmlNode countryNode in childNode)
                        {
                            if (countryNode.Name == "CountrySpendingSA")
                            {
                                countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                            }
                        }
                        break;
                }
            }

            return new ServerMessageDoBreakThroughOps(player, countriesSpendingSA);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<OperationalMove> returnValue = player.DoBreakThroughOps(this.player, countriesSpendingSA);
            List<Move> listOfMoves = new List<Move>();
            foreach (OperationalMove opMove in returnValue)
            {
                listOfMoves.Add(opMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoInitialStrategicMovement : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDoInitialStrategicMovement(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoInitialStrategicMovement;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoInitialStrategicMovement";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoInitialStrategicMovement Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoInitialStrategicMovement(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<StrategicMove> returnValue = player.DoInitialStrategicMovement(this.player);
            List<Move> listOfMoves = new List<Move>();
            foreach (StrategicMove stratMove in returnValue)
            {
                listOfMoves.Add(stratMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoNewCountryDeployment : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private MapInfo.CountryID country;

        public ServerMessageDoNewCountryDeployment(GameController.playerType player, MapInfo.CountryID country)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoNewCountryDeployment;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
            this.country = country;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoNewCountryDeployment";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("Country");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoNewCountryDeployment Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            MapInfo.CountryID country =  MapInfo.CountryID.BalticStates;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "Country":
                        country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoNewCountryDeployment(player, country);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<DeploymentMove> returnValue = player.DoNewCountryDeployment(this.player, country);
            List<Move> listOfMoves = new List<Move>();
            foreach (DeploymentMove deployMove in returnValue)
            {
                listOfMoves.Add(deployMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageAskForNavalInterception : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private SeaMoveOperationalMove seaMove;

        public ServerMessageAskForNavalInterception(GameController.playerType player, SeaMoveOperationalMove seaMove)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForNavalInterception;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
            this.player = player;
            this.seaMove = seaMove;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForNavalInterception";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("SeaMove");
            nodeToAdd.AppendChild(seaMove.Serialise(xml));
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageAskForNavalInterception Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            SeaMoveOperationalMove seaMove = null;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "SeaMove":
                        seaMove = (SeaMoveOperationalMove)SeaMoveOperationalMove.Deserialise(childNode.FirstChild);
                        break;
                }
            }

            return new ServerMessageAskForNavalInterception(player, seaMove);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.AskForNavalInterception(this.player, seaMove);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageReportForNavalInterception : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private MapInfo.RegionID regionID;
        private int numFriendlyHitsOn6;
        private int numFriendlyHitsOn56;
        private int numEnemyHitsOn6;
        private int numEnemyHitsOn56;
        private List<PlayingPiece> piecesTransported;
        private List<PlayingPiece> piecesLost;

        public ServerMessageReportForNavalInterception(GameController.playerType player, MapInfo.RegionID regionID, int numFriendlyHitsOn6, int numFriendlyHitsOn56, int numEnemyHitsOn6, int numEnemyHitsOn56, List<PlayingPiece> piecesTransported, List<PlayingPiece> piecesLost)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.ReportForNavalInterception;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
            this.player = player;
            this.regionID = regionID;
            this.numFriendlyHitsOn6 = numFriendlyHitsOn6;
            this.numFriendlyHitsOn56 = numFriendlyHitsOn56;
            this.numEnemyHitsOn6 = numEnemyHitsOn6;
            this.numEnemyHitsOn56 = numEnemyHitsOn56;
            if (piecesTransported != null)
                this.piecesTransported = new List<PlayingPiece>(piecesTransported);
            else
                this.piecesTransported = new List<PlayingPiece>();
            if (piecesLost != null)
                this.piecesLost = new List<PlayingPiece>(piecesLost);
            else
                this.piecesLost = new List<PlayingPiece>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageReportForNavalInterception";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumFriendlyHitsOn6");
            nodeToAdd.InnerText = numFriendlyHitsOn6.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumFriendlyHitsOn56");
            nodeToAdd.InnerText = numFriendlyHitsOn56.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumEnemyHitsOn6");
            nodeToAdd.InnerText = numEnemyHitsOn6.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumEnemyHitsOn56");
            nodeToAdd.InnerText = numEnemyHitsOn56.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("PiecesTransported");
            foreach (PlayingPiece playingPiece in piecesTransported)
            {
                System.Xml.XmlNode pieceNode = xml.CreateElement("PlayingPiece");
                if (playingPiece is Block)
                {
                    pieceNode.AppendChild(((Block)playingPiece).Serialise(xml));
                }
                else if (playingPiece is GroundSupportUnit)
                {
                    pieceNode.AppendChild(((GroundSupportUnit)playingPiece).Serialise(xml));
                }
                nodeToAdd.AppendChild(pieceNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("PiecesLost");
            foreach (PlayingPiece playingPiece in piecesLost)
            {
                System.Xml.XmlNode pieceNode = xml.CreateElement("PlayingPiece");
                if (playingPiece is Block)
                {
                    pieceNode.AppendChild(((Block)playingPiece).Serialise(xml));
                }
                else if (playingPiece is GroundSupportUnit)
                {
                    pieceNode.AppendChild(((GroundSupportUnit)playingPiece).Serialise(xml));
                }
                nodeToAdd.AppendChild(pieceNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageReportForNavalInterception Deserialise(System.Xml.XmlNode node)
        {
           GameController.playerType player = GameController.playerType.AlliedPlayer;
           MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
           int numFriendlyHitsOn6 = 0;
           int numFriendlyHitsOn56 = 0;
           int numEnemyHitsOn6 = 0;
           int numEnemyHitsOn56 = 0;
           List<PlayingPiece> piecesTransported = new List<PlayingPiece>();
           List<PlayingPiece> piecesLost = new List<PlayingPiece>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "RegionID":
                        regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                        break;
                    case "NumFriendlyHitsOn6":
                        numFriendlyHitsOn6 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumFriendlyHitsOn56":
                        numFriendlyHitsOn56 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumEnemyHitsOn6":
                        numEnemyHitsOn6 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumEnemyHitsOn56":
                        numEnemyHitsOn56 = Int32.Parse(childNode.InnerText);
                        break;
                    case "PiecesTransported":
                        foreach (System.Xml.XmlNode PieceNode in childNode)
                        {
                            if (PieceNode.Name == "PlayingPiece")
                            {
                                piecesTransported.Add(PlayingPiece.Deserialise(PieceNode.ChildNodes[0]));
                            }
                        }
                        break;
                    case "PiecesLost":
                        foreach (System.Xml.XmlNode PieceNode in childNode)
                        {
                            if (PieceNode.Name == "PlayingPiece")
                            {
                                piecesLost.Add(PlayingPiece.Deserialise(PieceNode.ChildNodes[0]));
                            }
                        }
                        break;
                }
            }

            return new ServerMessageReportForNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.ReportNavalInterception(this.player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageDoBreakThroughCombat : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private List<MapInfo.CountryID> countriesSpendingSA;
        private bool followingFromBreakThroughOps;
        private MapInfo.RegionID breakThroughOpsRegion;

        public ServerMessageDoBreakThroughCombat(GameController.playerType player, List<MapInfo.CountryID> countriesSpendingSA, bool followingFromBreakThroughOps, MapInfo.RegionID breakThroughOpsRegion)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoBreakThroughCombat;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
            this.followingFromBreakThroughOps = followingFromBreakThroughOps;
            this.breakThroughOpsRegion = breakThroughOpsRegion;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoBreakThroughCombat";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            System.Xml.XmlNode CountriesSpendingSANode = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSANode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSANode);

            nodeToAdd = xml.CreateElement("FollowingFromBreakThroughOps");
            nodeToAdd.InnerText = followingFromBreakThroughOps.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("BreakThroughOpsRegion");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), breakThroughOpsRegion);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoBreakThroughCombat Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();
            bool followingFromBreakThroughOps = false;
            MapInfo.RegionID breakThroughOpsRegion = MapInfo.RegionID.Albania;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "CountriesSpendingSA":
                        foreach (System.Xml.XmlNode countryNode in childNode)
                        {
                            if (countryNode.Name == "CountrySpendingSA")
                            {
                                countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                            }
                        }
                        break;
                    case "FollowingFromBreakThroughOps":
                        followingFromBreakThroughOps = bool.Parse(childNode.InnerText);
                        break;
                    case "BreakThroughOpsRegion":
                        breakThroughOpsRegion = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoBreakThroughCombat(player, countriesSpendingSA, followingFromBreakThroughOps, breakThroughOpsRegion);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            CombatMove returnValue = player.DoBreakThroughCombat(this.player, countriesSpendingSA, followingFromBreakThroughOps, breakThroughOpsRegion);
            List<Move> listOfMoves = new List<Move>();
            listOfMoves.Add(returnValue);
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoInitialCombatPhase : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDoInitialCombatPhase(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoInitialCombatPhase;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoInitialCombatPhase";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoInitialCombatPhase Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoInitialCombatPhase(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<CombatMove> returnValue = player.DoInitialCombatPhase(this.player);
            List<Move> listOfMoves = new List<Move>();
            foreach (CombatMove combatMove in returnValue)
            {
                listOfMoves.Add(combatMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageAskForGSUCombatCasualties : ServerMessagePlayerCall
    {
        private GameController.playerType playerAssigningCasualties;
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private List<int> defendingDieRolls;
        private List<int> attackingDieRolls;
        private bool breakThrough;
        private List<MapInfo.CountryID> countriesSpendingSA;

        public ServerMessageAskForGSUCombatCasualties(GameController.playerType playerAssigningCasualties, GameController.playerType defendingPlayer, MapInfo.RegionID regionID, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, List<int> defendingDieRolls, List<int> attackingDieRolls, bool breakThrough, List<MapInfo.CountryID> countriesSpendingSA)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForGSUCombatCasualties;
            serverMessageExpected = TCPServer.ServerRequestMessage.AskForGSUCombatCasualtiesReturn;
            this.playerAssigningCasualties = playerAssigningCasualties;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if(attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID,int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (defendingDieRolls != null)
                this.defendingDieRolls = new List<int>(defendingDieRolls);
            else
                this.defendingDieRolls = new List<int>();
            if (attackingDieRolls != null)
                this.attackingDieRolls = new List<int>(attackingDieRolls);
            else
                this.attackingDieRolls = new List<int>();
            this.breakThrough = breakThrough;
            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForGSUCombatCasualties";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("PlayerAssigningCasualties");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), playerAssigningCasualties);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingPlayer");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                nodeToAdd.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                nodeToAdd.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingDieRolls");
            foreach (int dieRoll in this.defendingDieRolls)
            {
                System.Xml.XmlNode DieRollNode = xml.CreateElement("DieRoll");
                DieRollNode.InnerText = dieRoll.ToString();
                nodeToAdd.AppendChild(DieRollNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("AttackingDieRolls");
            foreach (int dieRoll in this.attackingDieRolls)
            {
                System.Xml.XmlNode DieRollNode = xml.CreateElement("DieRoll");
                DieRollNode.InnerText = dieRoll.ToString();
                nodeToAdd.AppendChild(DieRollNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("BreakThrough");
            nodeToAdd.InnerText = breakThrough.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                nodeToAdd.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageAskForGSUCombatCasualties Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType playerAssigningCasualties = GameController.playerType.AlliedPlayer;
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID,int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID,int>();
            List<int> defendingDieRolls = new List<int>();
            List<int> attackingDieRolls = new List<int>();
            bool breakThrough = false;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "PlayerAssigningCasualties":
                        playerAssigningCasualties = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "DefendingPlayer":
                        defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case  "DefendingGSUSelections":
                        foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                        {
                            defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                        }
                        break;
                    case "AttackingGSUSelections":
                        foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                        {
                            attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                        }
                        break;
                    case "DefendingDieRolls":
                        foreach (System.Xml.XmlNode DieRollNode in childNode)
                        {
                            defendingDieRolls.Add(Int32.Parse(DieRollNode.InnerText));
                        }
                        break;
                    case "AttackingDieRolls":
                        foreach (System.Xml.XmlNode DieRollNode in childNode)
                        {
                            attackingDieRolls.Add(Int32.Parse(DieRollNode.InnerText));
                        }
                        break;
                    case "CountriesSpendingSA":
                        foreach (System.Xml.XmlNode countryNode in childNode)
                        {
                            if (countryNode.Name == "CountrySpendingSA")
                            {
                                countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                            }
                        }
                        break;
                    case "RegionID":
                            regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                            break;
                }
            }

            return new ServerMessageAskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            Dictionary<MapInfo.CountryID, int> returnValue = player.AskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);
            return new ClientMessageAskForGSUCombatCasualtiesReturn(returnValue);
        }
    };

    class ServerMessageAskAttackerToAssignLosses : ServerMessagePlayerCall
    {
        private GameController.playerType attackingPlayer;
        private MapInfo.RegionID regionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private int numInfantryLosses;
        private int numArmorLosses;
        private bool counterAttack;
        private List<MapInfo.CountryID> countriesSpendingSAInBattle;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ServerMessageAskAttackerToAssignLosses(GameController.playerType attackingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAInBattle, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskAttackerToAssignLosses;
            serverMessageExpected = TCPServer.ServerRequestMessage.AssignLossesReturn;
            this.attackingPlayer = attackingPlayer;
            this.regionID = regionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.numInfantryLosses = numInfantryLosses;
            this.numArmorLosses = numArmorLosses;
            this.counterAttack = counterAttack;
            if (countriesSpendingSAInBattle != null)
                this.countriesSpendingSAInBattle = new List<MapInfo.CountryID>(countriesSpendingSAInBattle);
            else
                this.countriesSpendingSAInBattle = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskAttackerToAssignLosses";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode AttackingPlayerNode = xml.CreateElement("AttackingPlayer");
            AttackingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), attackingPlayer);
            nodeToReturn.AppendChild(AttackingPlayerNode);

            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode NumInfantryLossesNode = xml.CreateElement("NumInfantryLosses");
            NumInfantryLossesNode.InnerText = numInfantryLosses.ToString();
            nodeToReturn.AppendChild(NumInfantryLossesNode);

            System.Xml.XmlNode NumArmorLossesNode = xml.CreateElement("NumArmorLosses");
            NumArmorLossesNode.InnerText = numArmorLosses.ToString();
            nodeToReturn.AppendChild(NumArmorLossesNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("CountriesSpendingSAInBattle");
            foreach (MapInfo.CountryID country in countriesSpendingSAInBattle)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                nodeToAdd.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskAttackerToAssignLosses Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType attackingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            int numInfantryLosses = 0;
            int numArmorLosses = 0;
            bool counterAttack = false;
            List<MapInfo.CountryID> countriesSpendingSAInBattle = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "AttackingPlayer")
                    attackingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "NumInfantryLosses")
                    numInfantryLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumArmorLosses")
                    numArmorLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if(childNode.Name == "CountriesSpendingSAInBattle")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSAInBattle.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }

                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ServerMessageAskAttackerToAssignLosses(attackingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            Dictionary<PlayingPiece, int> returnValue = player.AskAttackerToAssignLosses(attackingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);
            return new ClientMessageAssignLossesReturn(returnValue);
        }
    };

    class ServerMessageAskDefenderForRetreatBeforeCombatMoves : ServerMessagePlayerCall
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ServerMessageAskDefenderForRetreatBeforeCombatMoves(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskDefenderForRetreatBeforeCombatMoves;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskDefenderForRetreatBeforeCombatMoves";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("DefendingPlayer");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMove");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                nodeToAdd.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageAskDefenderForRetreatBeforeCombatMoves Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>(); 
            
            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if(childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach(System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.FirstChild));
                    }
                }
            }

            return new ServerMessageAskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<OperationalMove> returnValue = player.AskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);
            List<Move> listOfMoves = new List<Move>();
            foreach (OperationalMove opMove in returnValue)
            {
                listOfMoves.Add(opMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageAskForBreakThroughOption : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private bool canBreakthroughCombat;

        public ServerMessageAskForBreakThroughOption(GameController.playerType player, bool canBreakthroughCombat)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForBreakThroughOption;
            serverMessageExpected = TCPServer.ServerRequestMessage.AskForBreakThroughOptionReturn;
            this.player = player;
            this.canBreakthroughCombat = canBreakthroughCombat;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForBreakThroughOption";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("CanBreakthroughCombat");
            nodeToAdd.InnerText = canBreakthroughCombat.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageAskForBreakThroughOption Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            bool canBreakthroughCombat = false;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "CanBreakthroughCombat")
                    canBreakthroughCombat = bool.Parse(childNode.InnerText);
            }

            return new ServerMessageAskForBreakThroughOption(player, canBreakthroughCombat);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            GameController.breakThroughSelection returnValue = player.AskForBreakThroughOption(this.player, canBreakthroughCombat);
            return new ClientMessageAskForBreakThroughOptionReturn(returnValue.breakthroughPhase, returnValue.specialActionsSpent);
        }
    };

    class ServerMessageDoBreakThroughStrategicMovement : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDoBreakThroughStrategicMovement(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoBreakThroughStrategicMovement;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoBreakThroughStrategicMovement";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoBreakThroughStrategicMovement Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoBreakThroughStrategicMovement(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<StrategicMove> returnValue = player.DoBreakThroughStrategicMovement(this.player);
            List<Move> listOfMoves = new List<Move>();
            foreach (StrategicMove stratMove in returnValue)
            {
                listOfMoves.Add(stratMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageInformPlayerOfConquest : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private MapInfo.CountryID country;

        public ServerMessageInformPlayerOfConquest(GameController.playerType player, MapInfo.CountryID country)
        {
            this.player = player;
            this.country = country;
            this.clientMessageToReturn = TCPClient.ClientMessageType.InformPlayerOfConquest;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageInformPlayerOfConquest";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("PlayerType");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("Country");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageInformPlayerOfConquest Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            MapInfo.CountryID country = MapInfo.CountryID.BalticStates;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "PlayerType")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "Country")
                    country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), childNode.InnerText);
            }

            return new ServerMessageInformPlayerOfConquest(player, country);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            player.InformPlayerOfConquest(this.player, country);
            return null;
        }
    };

    class ServerMessageDoFleetPointTransfers : ServerMessagePlayerCall
    {
        private GameController.playerType player;

        public ServerMessageDoFleetPointTransfers(GameController.playerType player)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoFleetPointTransfers;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoFleetPointTransfers";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoFleetPointTransfers Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoFleetPointTransfers(player);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<FleetTransferMove> returnValue = player.DoFleetPointTransfers(this.player);
            List<Move> listOfMoves = new List<Move>();
            foreach (FleetTransferMove fleetMove in returnValue)
            {
                listOfMoves.Add(fleetMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageDoFortressOverStackMoves : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private MapInfo.RegionID regionID;
        private int numBlocksToMove;

        public ServerMessageDoFortressOverStackMoves(GameController.playerType player, MapInfo.RegionID regionID, int numBlocksToMove)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoFortressOverStackMoves;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
            this.player = player;
            this.regionID = regionID;
            this.numBlocksToMove = numBlocksToMove;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoFortressOverStackMoves";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumBlocksToMove");
            nodeToAdd.InnerText = numBlocksToMove.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageDoFortressOverStackMoves Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            int numBlocksToMove = 0;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "RegionID":
                        regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                        break;
                    case "NumBlocksToMove":
                        numBlocksToMove = Int32.Parse(childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageDoFortressOverStackMoves(player, regionID, numBlocksToMove);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<MovePieceOperationalMove> returnValue = player.DoFortressOverStackMoves(this.player, regionID, numBlocksToMove);
            List<Move> listOfMoves = new List<Move>();
            foreach (MovePieceOperationalMove opMove in returnValue)
            {
                listOfMoves.Add(opMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageAskAxisPlayerForVichy : ServerMessagePlayerCall
    {
        public ServerMessageAskAxisPlayerForVichy()
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskAxisPlayerForVichy;
            serverMessageExpected = TCPServer.ServerRequestMessage.boolReturn;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskAxisPlayerForVichy";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            return nodeToReturn;
        }

        public new static ServerMessageAskAxisPlayerForVichy Deserialise(System.Xml.XmlNode node)
        {
            return new ServerMessageAskAxisPlayerForVichy();
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            bool returnValue = player.AskAxisPlayerForVichy();
            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ServerMessageInformPlayer : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private string information;
        public ServerMessageInformPlayer(GameController.playerType player, string information)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskAxisPlayerForVichy;
            this.player = player;
            this.information = information;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageInformPlayer";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("Information");
            nodeToAdd.InnerText = information;
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageInformPlayer Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            string information = "";

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "Information":
                        information = childNode.InnerText;
                        break;
                }
            }

            return new ServerMessageInformPlayer(player, information);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            player.InformPlayer(this.player, information);
            return null;
        }
    };

    class ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses : ServerMessagePlayerCall
    {
        public ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses()
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DoAxisRedeploymentOfSovietUpFrontDefenses;
            serverMessageExpected = TCPServer.ServerRequestMessage.MovesReturn;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDoFleetPointTransfers";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            return nodeToReturn;
        }

        public new static ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses Deserialise(System.Xml.XmlNode node)
        {
            return new ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses();
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            List<SovietUpFrontDefenseRedeploymentMove> returnValue = player.DoAxisRedeploymentOfSovietUpFrontDefenses();
            List<Move> listOfMoves = new List<Move>();
            foreach (SovietUpFrontDefenseRedeploymentMove sovietUpFrontRedeploymentMove in returnValue)
            {
                listOfMoves.Add(sovietUpFrontRedeploymentMove);
            }
            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ServerMessageInformPlayerOfVictory : ServerMessagePlayerCall
    {
        private GameController.playerType player;
        private GameController.Victory victory;
        public ServerMessageInformPlayerOfVictory(GameController.playerType player, GameController.Victory victory)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.InformPlayerOfVictory;
            this.player = player;
            this.victory = victory;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageInformPlayerOfVictory";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("Victory");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.Victory), victory);
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ServerMessageInformPlayerOfVictory Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            GameController.Victory victory = GameController.Victory.AlliedDecisiveVictory;

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "Victory":
                        victory = (GameController.Victory)Enum.Parse(typeof(GameController.Victory), childNode.InnerText);
                        break;
                }
            }

            return new ServerMessageInformPlayerOfVictory(player, victory);
        }

        public override ClientMessage CallPlayer(IPlayer player)
        {
            player.InformPlayerOfVictory(this.player, victory);
            return null;
        }
    };

    class ServerMessageAssignLossesReturn : ServerMessage
    {
        public Dictionary<PlayingPiece, int> losses;

        public ServerMessageAssignLossesReturn(Dictionary<PlayingPiece, int> losses)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AssignLossesReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            if (losses != null)
                this.losses = new Dictionary<PlayingPiece, int>(losses);
            else
                this.losses = new Dictionary<PlayingPiece, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "AskAttackerToAssignLossesReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode LossesNode = xml.CreateElement("Losses");
            foreach (PlayingPiece piece in this.losses.Keys)
            {
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode CasualtyNode = xml.CreateElement("Casualty");
                numberAttr.Value = this.losses[piece].ToString();
                if (piece is Block)
                    CasualtyNode.AppendChild(((Block)piece).Serialise(xml));
                else if (piece is GroundSupportUnit)
                    CasualtyNode.AppendChild(((GroundSupportUnit)piece).Serialise(xml));
                CasualtyNode.Attributes.Append(numberAttr);
                LossesNode.AppendChild(CasualtyNode);
            }
            nodeToReturn.AppendChild(LossesNode);

            return nodeToReturn;
        }

        public new static ServerMessageAssignLossesReturn Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<PlayingPiece, int> losses = new Dictionary<PlayingPiece, int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Losses")
                {
                    foreach (System.Xml.XmlNode CasualtyNode in childNode)
                    {
                        losses.Add(PlayingPiece.Deserialise(CasualtyNode.FirstChild), Int32.Parse(CasualtyNode.Attributes["number"].Value));
                    }
                }
            }

            return new ServerMessageAssignLossesReturn(losses);
        }
    };

    class ServerMessageAssignBoolReturn : ServerMessage
    {
        public bool returnValue;

        public ServerMessageAssignBoolReturn(bool returnValue)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.boolReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            this.returnValue = returnValue;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAssignBoolReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode ReturnValueNode = xml.CreateElement("ReturnValue");
            ReturnValueNode.InnerText = returnValue.ToString();
            nodeToReturn.AppendChild(ReturnValueNode);

            return nodeToReturn;
        }

        public new static ServerMessageAssignBoolReturn Deserialise(System.Xml.XmlNode node)
        {
            bool returnValue = false;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ReturnValue")
                {
                    returnValue = bool.Parse(childNode.InnerText);
                }
            }

            return new ServerMessageAssignBoolReturn(returnValue);
        }
    };

    class ServerMessageDeploymentMovesReturn : ServerMessage
    {
        public List<DeploymentMove> returnValue;

        public ServerMessageDeploymentMovesReturn(List<DeploymentMove> returnValue)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.DeploymentMovesReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            if (returnValue != null)
                this.returnValue = new List<DeploymentMove>(returnValue);
            else
                this.returnValue = new List<DeploymentMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageDeploymentMovesReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode ReturnValueNode = xml.CreateElement("ReturnValue");
            foreach(DeploymentMove move in returnValue)
            {
                System.Xml.XmlNode DeploymentMoveNode = xml.CreateElement("DeployMove");
                DeploymentMoveNode.AppendChild(move.Serialise(xml));
                ReturnValueNode.AppendChild(DeploymentMoveNode);
            }
            nodeToReturn.AppendChild(ReturnValueNode);

            return nodeToReturn;
        }

        public new static ServerMessageDeploymentMovesReturn Deserialise(System.Xml.XmlNode node)
        {
            List<DeploymentMove> returnValue  = new List<DeploymentMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ReturnValue")
                {
                    foreach(System.Xml.XmlNode DeploymentMoveNode in childNode)
                    {
                        if(DeploymentMoveNode.Name == "DeployMove")
                        {
                            returnValue.Add((DeploymentMove)Move.Deserialise(DeploymentMoveNode.FirstChild));
                        }
                    }
                }
            }

            return new ServerMessageDeploymentMovesReturn(returnValue);
        }
    };

    class ServerMessageAskForDefenderOptionsReturn : ServerMessage
    {
        public GameController.defenderOptions defenderOptions;

        public ServerMessageAskForDefenderOptionsReturn(GameController.defenderOptions defenderOptions)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForDefenderOptionsReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            if (defenderOptions.defenderGSUSelections != null)
                this.defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>(defenderOptions.defenderGSUSelections);
            else
                this.defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();

            this.defenderOptions.defenderReinforceBattle = defenderOptions.defenderReinforceBattle;
            if (defenderOptions.defenderReinforceBattleMoves != null)
                this.defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>(defenderOptions.defenderReinforceBattleMoves);
            else
                this.defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>();
            this.defenderOptions.retreatBeforeCombat = defenderOptions.retreatBeforeCombat;
            if (defenderOptions.specialActionsSpentOnReinforcements != null)
                this.defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>(defenderOptions.specialActionsSpentOnReinforcements);
            else
                this.defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForDefenderOptionsReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode DefenderGSUSelectionsNode = xml.CreateElement("DefenderGSUSelections");
            foreach (MapInfo.CountryID country in this.defenderOptions.defenderGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelectionNode");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defenderOptions.defenderGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefenderGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefenderGSUSelectionsNode);

            System.Xml.XmlNode DefenderReinforceBattleNode = xml.CreateElement("DefenderReinforceBattle");
            DefenderReinforceBattleNode.InnerText = this.defenderOptions.defenderReinforceBattle.ToString();
            nodeToReturn.AppendChild(DefenderReinforceBattleNode);

            System.Xml.XmlNode DefenderReinforceBattleMovesNode = xml.CreateElement("DefenderReinforceBattleMoves");
            foreach (OperationalMove opMove in this.defenderOptions.defenderReinforceBattleMoves)
            {
                System.Xml.XmlNode ReinforceBattleMoveNode = xml.CreateElement("ReinforceBattleMove");
                ReinforceBattleMoveNode.AppendChild(opMove.Serialise(xml));
                DefenderReinforceBattleMovesNode.AppendChild(ReinforceBattleMoveNode);
            }
            nodeToReturn.AppendChild(DefenderReinforceBattleMovesNode);

            System.Xml.XmlNode RetreatBeforeCombatNode = xml.CreateElement("RetreatBeforeCombat");
            RetreatBeforeCombatNode.InnerText = this.defenderOptions.retreatBeforeCombat.ToString();
            nodeToReturn.AppendChild(RetreatBeforeCombatNode);

            System.Xml.XmlNode SpecialActionsSpentOnReinforcementsNode = xml.CreateElement("SpecialActionsSpentOnReinforcements");
            foreach (MapInfo.CountryID country in this.defenderOptions.specialActionsSpentOnReinforcements.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode SpecialActionNode = xml.CreateElement("SpecialActionNode");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defenderOptions.specialActionsSpentOnReinforcements[country].ToString();
                SpecialActionNode.Attributes.Append(countryAttr);
                SpecialActionNode.Attributes.Append(numberAttr);
                SpecialActionsSpentOnReinforcementsNode.AppendChild(SpecialActionNode);
            }
            nodeToReturn.AppendChild(SpecialActionsSpentOnReinforcementsNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskForDefenderOptionsReturn Deserialise(System.Xml.XmlNode node)
        {
            GameController.defenderOptions defenderOptions = new GameController.defenderOptions();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefenderGSUSelections")
                {
                    defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defenderOptions.defenderGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "DefenderReinforceBattle")
                    defenderOptions.defenderReinforceBattle = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefenderReinforceBattleMoves")
                {
                    defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>();
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        if (OpMoveNode.Name == "ReinforceBattleMove")
                        {
                            defenderOptions.defenderReinforceBattleMoves.Add((OperationalMove)OperationalMove.Deserialise(OpMoveNode.ChildNodes[0]));
                        }
                    }
                }
                if (childNode.Name == "RetreatBeforeCombat")
                    defenderOptions.retreatBeforeCombat = bool.Parse(childNode.InnerText);

                if (childNode.Name == "SpecialActionsSpentOnReinforcements")
                {
                    defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode SpecialActionNode in childNode)
                    {
                        defenderOptions.specialActionsSpentOnReinforcements.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), SpecialActionNode.Attributes["country"].Value), Int32.Parse(SpecialActionNode.Attributes["number"].Value));
                    }
                }
            }

            return new ServerMessageAskForDefenderOptionsReturn(defenderOptions);
        }
    };

    class ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn : ServerMessage
    {
        public List<OperationalMove> listOfOpMoves;

        public ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn(List<OperationalMove> listOfOpMoves)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskDefenderForRetreatBeforeCombatMovesReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            if (listOfOpMoves != null)
                this.listOfOpMoves = new List<OperationalMove>(listOfOpMoves);
            else
                this.listOfOpMoves = new List<OperationalMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode ListOfOpMovesNode = xml.CreateElement("ListOfOpMoves");
            foreach (OperationalMove opMove in listOfOpMoves)
            {
                System.Xml.XmlNode OpMoveNode = xml.CreateElement("OperationalMove");
                OpMoveNode.AppendChild(opMove.Serialise(xml));
                ListOfOpMovesNode.AppendChild(OpMoveNode);
            }
            nodeToReturn.AppendChild(ListOfOpMovesNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn Deserialise(System.Xml.XmlNode node)
        {
            List<OperationalMove> ListOfOpMoves = new List<OperationalMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ListOfOpMoves")
                {
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        ListOfOpMoves.Add((OperationalMove)OperationalMove.Deserialise(OpMoveNode.ChildNodes[0]));
                    }
                }
            }

            return new ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn(ListOfOpMoves);
        }
    };

    class ServerMessageAskForGSUCombatCasualtiesReturn : ServerMessage
    {
        public Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties;

        public ServerMessageAskForGSUCombatCasualtiesReturn(Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AskForGSUCombatCasualtiesReturn;
            serverMessageExpected = TCPServer.ServerRequestMessage.Polling;
            if (listOfGSUCombatCasualties != null)
                this.listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>(listOfGSUCombatCasualties);
            else
                this.listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskForGSUCombatCasualtiesReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode ListOfGSUCombatCasualtiesNode = xml.CreateElement("ListOfGSUCombatCasualties");
            foreach (MapInfo.CountryID country in listOfGSUCombatCasualties.Keys)
            {
                System.Xml.XmlNode GSUCombatCasualtyNode = xml.CreateElement("GSUCombatCasualty");
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.listOfGSUCombatCasualties[country].ToString();
                GSUCombatCasualtyNode.Attributes.Append(countryAttr);
                GSUCombatCasualtyNode.Attributes.Append(numberAttr);
                ListOfGSUCombatCasualtiesNode.AppendChild(GSUCombatCasualtyNode);
            }
            nodeToReturn.AppendChild(ListOfGSUCombatCasualtiesNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskForGSUCombatCasualtiesReturn Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ListOfGSUCombatCasualties")
                {
                    foreach (System.Xml.XmlNode GSUCombatCasualtyNode in childNode)
                    {
                        listOfGSUCombatCasualties.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUCombatCasualtyNode.Attributes["country"].Value), Int32.Parse(GSUCombatCasualtyNode.Attributes["number"].Value));
                    }
                }
            }

            return new ServerMessageAskForGSUCombatCasualtiesReturn(listOfGSUCombatCasualties);
        }
    };

    class ServerMessageAskDefenderForCounterAttackReturn : ServerMessage
    {
        public GameController.defenderCounterAttackOptions counterAttackOptions;

        public ServerMessageAskDefenderForCounterAttackReturn(GameController.defenderCounterAttackOptions counterAttackOptions)
        {
            this.clientMessageToReturn = TCPClient.ClientMessageType.AssignLossesReturn;
            this.counterAttackOptions.assault = counterAttackOptions.assault;
            this.counterAttackOptions.defenderCounterAttacked = counterAttackOptions.defenderCounterAttacked;
            if (counterAttackOptions.defenderGSUSelections != null)
                this.counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>(counterAttackOptions.defenderGSUSelections);
            else
                this.counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (counterAttackOptions.listOfCounterAttackingMoves != null)
                this.counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>(counterAttackOptions.listOfCounterAttackingMoves);
            else
                this.counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>();
            if (counterAttackOptions.specialActionsSpent != null)
                this.counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>(counterAttackOptions.specialActionsSpent);
            else
                this.counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ServerMessageAskDefenderForCounterAttackReturn";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = counterAttackOptions.assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefenderCounterAttackedNode = xml.CreateElement("DefenderCounterAttacked");
            DefenderCounterAttackedNode.InnerText = counterAttackOptions.defenderCounterAttacked.ToString();
            nodeToReturn.AppendChild(DefenderCounterAttackedNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.counterAttackOptions.defenderGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.counterAttackOptions.defenderGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode ListOfCounterAttackingMovesNode = xml.CreateElement("ListOfCounterAttackingMoves");
            foreach (MovePieceOperationalMove opMove in this.counterAttackOptions.listOfCounterAttackingMoves)
            {
                System.Xml.XmlNode CounterAttackMoveNode = xml.CreateElement("CounterAttackMove");
                CounterAttackMoveNode.AppendChild(opMove.Serialise(xml));
                ListOfCounterAttackingMovesNode.AppendChild(CounterAttackMoveNode);
            }
            nodeToReturn.AppendChild(ListOfCounterAttackingMovesNode);

            System.Xml.XmlNode SpecialActionsSpentNode = xml.CreateElement("SpecialActionsSpent");
            foreach (MapInfo.CountryID country in counterAttackOptions.specialActionsSpent)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                SpecialActionsSpentNode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(SpecialActionsSpentNode);

            return nodeToReturn;
        }

        public new static ServerMessageAskDefenderForCounterAttackReturn Deserialise(System.Xml.XmlNode node)
        {
            GameController.defenderCounterAttackOptions counterAttackOptions = new GameController.defenderCounterAttackOptions();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Assault")
                    counterAttackOptions.assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefenderCounterAttacked")
                    counterAttackOptions.defenderCounterAttacked = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        counterAttackOptions.defenderGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "ListOfCounterAttackingMoves")
                {
                    counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>();
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        if (OpMoveNode.Name == "CounterAttackMove")
                        {
                            counterAttackOptions.listOfCounterAttackingMoves.Add((MovePieceOperationalMove)MovePieceOperationalMove.Deserialise(OpMoveNode.ChildNodes[0]));
                        }
                    }
                }
                if (childNode.Name == "SpecialActionsSpent")
                {
                    counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>();
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            counterAttackOptions.specialActionsSpent.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
            }

            return new ServerMessageAskDefenderForCounterAttackReturn(counterAttackOptions);
        }
    };
}
